2012-10-20 7 views
18

Was ist die beste Möglichkeit, ein Wörterbuch in zwei Hälften zu teilen?Ein Wörterbuch in 2 Wörterbücher aufteilen

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

Ich bin auf der Suche, dies zu tun:

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

Es spielt keine Rolle, welche Schlüssel/Werte in jedem Wörterbuch gehen. Ich suche einfach nach dem einfachsten Weg, ein Wörterbuch in zwei Teile zu teilen.

+2

Was ist Ihre Definition von * in zwei *, meinst du die Hälfte der Schlüssel in jedem Wörterbuch? –

Antwort

17

Dies würde funktionieren, obwohl ich nicht kanten Fälle prüfte:

>>> 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

Edge Fälle sind kein Problem; Außerhalb des Bereichs liegende Segmente geben nur leere Listen zurück, und wenn dict in einer leeren Liste aufgerufen wird, wird ein leeres Wörterbuch zurückgegeben. JEDOCH: http://docs.python.org/library/stdtypes.html#dict.items scheint darauf hinzuweisen, dass die Python-Spezifikation nicht garantiert, dass Aufrufe von items() die Paare jedes Mal in der gleichen Reihenfolge zurückgeben! Vielleicht sollten wir, um theoretisch korrekt zu sein, das Ergebnis eines Aufrufs von items() speichern und dann das gespeicherte Ergebnis aufteilen? –

+0

@MarkAmery Ich glaube, dass sie garantiert stabil sind, dh sie werden in der gleichen Reihenfolge zurückkehren, solange nichts das Wörterbuch ändert, obwohl diese Reihenfolge willkürlich ist, so dass dies alles in Ordnung bringen sollte. –

+0

@Lattyware Was Sie gerade gesagt haben, ist in den Dokumenten als CPython-wahr aufgeführt. Durch die Auslassung wird angedeutet, dass andere Python-Implementierungen dies theoretisch nicht garantieren müssen. Zugegeben, es ist schwer, sich eine vernünftige Implementierung vorzustellen, in der dies nicht der Fall war, also ist es wirklich nur ein theoretisches Problem ... –

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, aber '{key: d [key] für i, Schlüssel in enumerate (d)' usw. wäre noch einfacher. – georg

5

Hier ist ein Weg, es zu tun, einen Iterator über die Elemente im Wörterbuch verwendet und 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

Wir dies effizient tun können, mit itertools.zip_longest() (dies zu beachten ist 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) 

Was uns gibt:

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

Warum der Downvote dazu? –

2

Wenn Sie python +3.3 verwenden, und möchten Ihre gespaltet Wörterbücher das gleiche in verschiedenen Python Anrufungen sein, nicht .items verwenden, da die Hash-Werte der Schlüssel, der bestimmt, Die Reihenfolge .items() wird zwischen Pythonaufrufen geändert. Siehe Hash randomization


1

Hier ist die Funktion, die verwendet werden können, um ein Wörterbuch zu allen Divisionen aufgeteilt.

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 hat nicht für mich funktioniert. Ich musste in eine Liste umwandeln, bevor ich das Ergebnis des .items() - Aufrufs indexieren konnte. (Ich bin mit Python 3.6 im Beispiel)

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} 
""" 

Beachten Sie die dicts sind nicht unbedingt in der Reihenfolge der Erstellung gespeichert, so dass die Indizes werden gemischt werden.

Verwandte Themen