2016-04-01 15 views
0

ich dict haben, sagen wir zum Beispiel diesegibt es eine bessere Möglichkeit, ein Diktat zu bereinigen?

data={k:k for k in range(20)} 

ich eine Operation über den Werten von data und einige der en sich wie 0, zum Beispiel diese

for k,v in data.items(): 
    data[k] %= 2 

wenn dies zu tun Ich möchte alle Schlüssel, der einen Wert von 0, aber dabei in der Fliege gibt einen Fehler zu entfernen bekommen, damit ich es in am Ende zu tun habe, für die ich

tun
def clean(data): 
    while True: 
     try: 
      for k,v in data.items(): 
       if not v: 
        del data[k] 
      return 
     except RuntimeError: 
      pass 

meine Frage ist: es gibt eine bessere Möglichkeit, dies zu tun, so dass ich die Remotion in-Place und Vermeidung von zusätzlichen Speicher und besser noch in einer Reise machen ??

EDIT

das ist ähnlich wie meine beabsichtigte Verwendung

class MapDict(dict): 

    def __repr__(self): 
     return '{}({})'.format(self.__class__.__qualname__, super().__repr__()) 

    def map(self,func,*argv): 
     '''applicate func to every value in this MapDict''' 
     for k,v in self.items(): 
      self[k] = func(v,*argv) 
     self.clean() 

    def clean(self): 
     while True: 
      try: 
       for k,v in self.items(): 
        if not v: 
         del self[k] 
       return 
      except RuntimeError: 
       pass 


>>> data=MapDict((k,k) for k in range(20)) 
>>> data 
MapDict({0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19}) 
>>> from operator import add, mod 
>>> data.map(mod,2) 
>>> data 
MapDict({1: 1, 3: 1, 5: 1, 7: 1, 9: 1, 11: 1, 13: 1, 15: 1, 17: 1, 19: 1}) 
>>> data.map(add,10) 
>>> data 
MapDict({1: 11, 3: 11, 5: 11, 7: 11, 9: 11, 11: 11, 13: 11, 15: 11, 17: 11, 19: 11}) 
>>> 

damit ist, warum ich kein neues dict machen könnte, und ich möchte nur nur die relevanten Werte in meinem Beispiel halten , dass ich später etwas anderes brauche.

Gibt es einen besseren Weg, dies sauber zu machen? während es speicher effizient bleibt? und im geringsten Umfang der Reise?

+1

Siehe http://stackoverflow.com/questions/9023078/custom-dict-that-allows-delete-during-iteration – Stuart

+0

Sie wahrscheinlich nicht wollen, Unterklassen, so zu schreiben, ich sehe in würde zu einer der funktionalen Programmierbibliotheken (Toolz, Funcy usw.), die für die meisten dieser Funktionen nette Streaming-Funktionen bereitstellen. – tacaswell

+0

@tcaswell vielleicht Map ist ein schlechter Name für diese Methode, aber das ist genau das, was ich will, die Operation in-Place, aber 'toolz' gut aussehen für die Operationen, die ich tun, die nicht in-place sind – Copperfield

Antwort

1

Gibt es eine harte Anforderung es an Ort und Stelle zu tun, wenn nicht:

def clean(data): 
    return {k: v for k, v in data.items() if v} 

wenn ja

def clean(data): 
    remove_keys = tuple(k for k, v in data.items() if not v) 
    for k in remove_keys: 
     del data[k] 
+0

ja, ich speichereffizient sein wollen, so dass eine Kopie der Elemente erstellt wird, ist ein Nein – Copperfield

+1

Das dict-Verständnis erstellt keine Kopie der Elemente, macht nur einen weiteren Verweis auf die zugrunde liegenden Objekte. – tacaswell

+0

@Copperfield außer, dass ich ein Tupel anstelle einer Liste verwenden würde, sollte dies das Beste sein, das Sie bekommen können. Die zweite Implementierung kopiert nur (die Referenz auf/value), wenn die Bedingung (in diesem Fall "nicht v") wahr ist. – SleepProgger

2

Es ist nicht zu löschen Elemente aus einem Wörterbuch erlaubt, während sie über sie iterieren, aber Sie kann stattdessen über eine Kopie von Schlüsseln (oder Elementen) iterieren:

for k in list(data): 
    v = data[k] 
    if not v: 
     del data[k] 
+0

, aber eine Kopie des Schlüssels ist genau das, was ich vermeiden möchte, sonst würde ich diese Frage – Copperfield

+2

@Copperfield nicht stellen. Sie können die Sequenz, über die Sie iterieren, nicht sicher ändern. Sie * müssen * über eine Kopie der Schlüssel iterieren. – chepner

2

Das nächste, was Sie zum Löschen der Ite bekommen konnten ms on the fly mit minimaler Speicherauslastung wäre, die Liste der zu löschenden Schlüssel während der ersten Schleife zu erstellen und sie anschließend alle zu löschen. Dann kopieren Sie nur die Schlüssel, die gelöscht werden.

keys_to_del = [] 
for k, v in data.items(): 
    data[k] %= 2 
    if data[k] == 0: 
     keys_to_del.append(k) 
for k in keys_to_del: 
    del data[k] 
+0

Sie könnten es ein bisschen kürzen, indem Sie tun: für k in Tupel (ik für ik, iv in data.items() wenn iv% 2 ​​== 0): ... Verwenden Sie iteritems für Python 2.7 – SleepProgger

+0

@SleepProgger Nein, das würde nicht Ändere die Werte nicht. Und warum ein Tupel benutzen? – Stuart

+0

Mit dem ... ersetzt mit "del data [k]" würde mein Code das gleiche wie deins tun. Die Erstellung von Tupeln sollte ein wenig schneller sein. – SleepProgger

Verwandte Themen