2012-10-20 20 views
18

Qual è il modo migliore per dividere un dizionario a metà?Dividere un dizionario in 2 dizionari

d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5} 

che sto cercando di fare questo:

d1 = {'key1': 1, 'key2': 2, 'key3': 3} 
d2 = {'key4': 4, 'key5': 5} 

Non importa che le chiavi/valori vanno in ogni dizionario. Sto semplicemente cercando il modo più semplice per dividere un dizionario in due.

+2

Qual è la sua definizione di * * in due, vuoi dire la metà dei tasti in ogni dizionario? –

risposta

17

Questo potrebbe funzionare, anche se non ho la prova edge-casi:

>>> d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5} 
>>> d1 = dict(d.items()[len(d)/2:]) 
>>> d2 = dict(d.items()[:len(d)/2]) 
>>> print d1 
{'key1': 1, 'key5': 5, 'key4': 4} 
>>> print d2 
{'key3': 3, 'key2': 2} 
+2

I casi limite non sono un problema; le fette fuori intervallo restituiscono solo liste vuote e la chiamata di dict su una lista vuota restituisce un dizionario vuoto. TUTTAVIA: http://docs.python.org/library/stdtypes.html#dict.items sembra indicare che la specifica di Python non garantisce che le chiamate a oggetti() restituirà le coppie nello stesso ordine ogni volta! Forse, per essere teoricamente corretti, dovremmo memorizzare il risultato di una chiamata a items() e quindi affettare quel risultato memorizzato? –

+0

@MarkAmery Credo che essi sono garantiti per essere stabile, che è torneranno nello stesso ordine fino a quando non cambia nulla il dizionario, anche se questo ordine è arbitrario, in modo che dovrebbe rendere questo tutto bene. –

+0

@Lattyware Quello che hai appena detto è elencato nei documenti come vero per CPython. Per omissione, è implicito che altre implementazioni Python non debbano, in teoria, garantire questo. Certo, è difficile immaginare un'implementazione sana in cui non fosse così, quindi è davvero un problema solo teorico ... –

3
d1 = {key: value for i, (key, value) in enumerate(d.viewitems()) if i % 2 == 0} 
d2 = {key: value for i, (key, value) in enumerate(d.viewitems()) if i % 2 == 1} 
+1

+1, ma '{chiave: d [chiave] per i, digitare enumerate (d)' ecc. Sarebbe ancora più semplice. – georg

5

Ecco un modo per farlo utilizzando un iteratore sugli elementi nel dizionario e itertools.islice:

import itertools 

def splitDict(d): 
    n = len(d) // 2   # length of smaller half 
    i = iter(d.items())  # alternatively, i = d.iteritems() works in Python 2 

    d1 = dict(itertools.islice(i, n)) # grab first n items 
    d2 = dict(i)      # grab the rest 

    return d1, d2 
0

possiamo farlo in modo efficiente con itertools.zip_longest() (notare che questo è itertools.izip_longest() in 2.x):

from itertools import zip_longest 
d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5} 
items1, items2 = zip(*zip_longest(*[iter(d.items())]*2)) 
d1 = dict(item for item in items1 if item is not None) 
d2 = dict(item for item in items2 if item is not None) 

Il che ci dà:

>>> d1 
{'key3': 3, 'key1': 1, 'key4': 4} 
>>> d2 
{'key2': 2, 'key5': 5} 
+0

Perché il downvote su questo? –

2

Se si utilizza python +3.3, e desidera che i dizionari di spacco per essere lo stesso attraverso diverse invocazioni pitone, non utilizzare .items, dal momento che l'hash-valori delle chiavi, che determina l'ordine di .items() cambierà tra le chiamate di python. Vedere Hash randomization


1

Ecco la funzione che può essere usato per dividere un dizionario per eventuali divisioni.

import math 

def linch_dict_divider(raw_dict, num): 
    list_result = [] 
    len_raw_dict = len(raw_dict) 
    if len_raw_dict > num: 
     base_num = len_raw_dict/num 
     addr_num = len_raw_dict % num 
     for i in range(num): 
      this_dict = dict() 
      keys = list() 
      if addr_num > 0: 
       keys = raw_dict.keys()[:base_num + 1] 
       addr_num -= 1 
      else: 
       keys = raw_dict.keys()[:base_num] 
      for key in keys: 
       this_dict[key] = raw_dict[key] 
       del raw_dict[key] 
      list_result.append(this_dict) 

    else: 
     for d in raw_dict: 
      this_dict = dict() 
      this_dict[d] = raw_dict[d] 
      list_result.append(this_dict) 

    return list_result 

myDict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5} 
print myDict 
myList = linch_dict_divider(myDict, 2) 
print myList 
0

The answer by jone non ha funzionato per me. Ho dovuto eseguire il cast in una lista prima di poter indicizzare il risultato della chiamata .items(). (Sono in esecuzione Python 3.6 nell'esempio)

d = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5} 
split_idx = 3 
d1 = dict(list(d.items())[:split_idx]) 
d2 = dict(list(d.items())[split_idx:]) 

""" 
output: 
d1 
{'one': 1, 'three': 3, 'two': 2} 
d2 
{'five': 5, 'four': 4} 
""" 

Nota i dicts non sono necessariamente memorizzati nell'ordine della creazione così gli indici possono essere scambiati.

Problemi correlati