it-swarm.com.de

Abbildung von Werten in einem Python-Wörterbuch

Mit einem Wörterbuch { k1: v1, k2: v2 ... } möchte ich { k1: f(v1), k2: f(v2) ... } erhalten, vorausgesetzt, ich übergebe eine Funktion f.

Gibt es eine solche eingebaute Funktion? Oder muss ich das tun?

dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()])

Im Idealfall würde ich einfach schreiben

my_dictionary.map_values(f)

oder

my_dictionary.mutate_values_with(f)

Das heißt, es ist mir egal, ob das Originalwörterbuch mutiert ist oder eine Kopie erstellt wird.

177
Tarrasch

Es gibt keine solche Funktion; Der einfachste Weg dazu ist ein Diktierverständnis:

my_dictionary = {k: f(v) for k, v in my_dictionary.items()}

Verwenden Sie in Python 2.7 die .iteritems()-Methode anstelle von .items(), um Speicherplatz zu sparen. Die Syntax des Diktierverständnisses wurde erst mit Python 2.7 eingeführt.

Beachten Sie, dass es in Listen auch keine solche Methode gibt. Sie müssten ein Listenverständnis oder die Funktion map() verwenden.

Daher können Sie auch die Funktion map() zur Verarbeitung Ihres Diktats verwenden:

my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems()))

aber das ist wirklich nicht lesbar.

262
Martijn Pieters

Diese Tools eignen sich hervorragend für diese einfache, aber sich wiederholende Logik.

http://toolz.readthedocs.org/de/latest/api.html#toolz.dicttoolz.valmap

Holen Sie sich genau dort, wo Sie sein wollen.

import toolz
def f(x):
  return x+1

toolz.valmap(f, my_list)
21
Jesse Smith

Sie können dies vor Ort tun, anstatt ein neues Diktat zu erstellen, was für große Wörterbücher vorzuziehen ist (wenn Sie keine Kopie benötigen).

def mutate_dict(f,d):
    for k, v in d.iteritems():
        d[k] = f(v)

my_dictionary = {'a':1, 'b':2}
mutate_dict(lambda x: x+1, my_dictionary)

führt zu my_dictionary mit:

{'a': 2, 'b': 3}
19
gens

Während meine ursprüngliche Antwort den Punkt verfehlt hat (indem versucht wurde, dieses Problem mit der Lösung für Zugriff auf den Schlüssel in der Factory of DefaultDict zu lösen), habe ich es überarbeitet, um eine tatsächliche Lösung für die vorliegende Frage vorzuschlagen.

Hier ist es:

class walkableDict(dict):
  def walk(self, callback):
    try:
      for key in self:
        self[key] = callback(self[key])
    except TypeError:
      return False
    return True

Verwendungszweck:

>>> d = walkableDict({ k1: v1, k2: v2 ... })
>>> d.walk(f)

Die Idee ist, das ursprüngliche Diktat zu subklassen, um ihm die gewünschte Funktionalität zu geben: "Zuordnen" einer Funktion über alle Werte.

Das Plus ist, dass dieses Wörterbuch verwendet werden kann, um die ursprünglichen Daten als dict zu speichern, während Daten auf Anforderung mit einem Rückruf umgewandelt werden.

Natürlich können Sie die Klasse und die Funktion beliebig benennen (der in dieser Antwort gewählte Name ist von der PHP-Funktion array_walk() inspiriert).

Hinweis: Weder der try-except-Block noch die return-Anweisungen sind für die Funktionalität zwingend erforderlich. Sie dienen dazu, das Verhalten des array_walk des PHP weiter zu imitieren.

4
7heo.tk

Aufgrund von PEP-0469 , das iteritems () in items () umbenannte, und PEP-3113 , das Tuple-Parameter entpackt entfernt hat, sollten Sie in Python 3.x eine Antwort von Martijn Pieters schreiben so was:

my_dictionary = dict(map(lambda item: (item[0], f(item[1]), my_dictionary.items()))
2
lucidyan

Ich kam gerade durch diesen Anwendungsfall. Ich habe die Antwort von gens implementiert und fügte einen rekursiven Ansatz hinzu, um Werte zu behandeln, die auch diktiert sind:

def mutate_dict_in_place(f, d):
    for k, v in d.iteritems():
        if isinstance(v, dict):
            mutate_dict_in_place(f, v)
        else:
            d[k] = f(v)

# Exemple handy usage
def utf8_everywhere(d):
    mutate_dict_in_place((
        lambda value:
            value.decode('utf-8')
            if isinstance(value, bytes)
            else value
        ),
        d
    )

my_dict = {'a': b'byte1', 'b': {'c': b'byte2', 'd': b'byte3'}}
utf8_everywhere(my_dict)
print(my_dict)

Dies kann nützlich sein, wenn Sie mit Json- oder YAML-Dateien arbeiten, die Zeichenfolgen als Bytes in Python 2 kodieren

0
Oyono

So vermeiden Sie die Indizierung aus Lambda heraus:

rval = dict(map(lambda kv : (kv[0], ' '.join(kv[1])), rval.iteritems()))

Sie können auch:

rval = dict(map(lambda(k,v) : (k, ' '.join(v)), rval.iteritems()))
0
yourstruly