2016-10-20 2 views
2

ein Wörterbuch haben besteht aus String oder WörterbücherFilter Python-Wörterbuch mit filter() zur Liste der Wörterbuchwerte

parameters = { 
"date": {'date':"2015-12-13"}, 
"name": "Nick", 
"product": "BT Adapter", 
"transaction-id": "" 
} 

Und ich brauche Liste wie ['2015-12-13', 'BT Adapter', 'Nick'] zu bekommen.

Wenn es keine Wörterbücher in ihm, print filter(lambda x: x if len(x) > 0 and type(x) is not dict else None, parameters.values()) funktioniert perfekt, aber mit Wörterbuch darin habe ich versucht, es ist Wert zu extrahieren, mit

print filter(lambda x: x if len(x) > 0 and type(x) is not dict else map(lambda y: x[y], x.keys()), parameters.values()) 

und i AttributeError: 'str' object has no attribute 'keys' erhalten. Wie können alle Werte extrahiert werden?

+3

'len (x)> 0 'ist 'False' für eine leere Zeichenkette, also wird der' else' Teil ausgeführt und 'str' hat keine Methode' keys'. –

+0

Nebenbei bemerkt, ist es idiomatischer, "not isinstance (x, dict)" zu verwenden als "type (x) ist dict". Die Bedeutung ist etwas anders, aber es ist näher an das, was Sie wollen. –

+0

Es wäre wirklich hilfreich, wenn Sie die Ausgabe bereitstellen würden, die Sie erhalten möchten, wenn Sie dieses Wörterbuch als Eingabe verwenden ... Es ist überhaupt nicht klar, wie Sie mit Wörterbuchwerten oder leeren Strings umgehen wollen ... BTW: 'map (lambda y: x [y], x.keys()) 'ist im Grunde genommen nur' x.values ​​() ' – Bakuriu

Antwort

1
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 


def magic(params): 
    dicts = [params] 
    values = [] 

    while len(dicts): 
     d = dicts.pop() 

     for value in d.values(): 
      if isinstance(value, dict): 
       dicts.append(value) 
      elif isinstance(value, basestring) and len(value) > 0: 
       values.append(value) 

    return values 


def main(): 
    parameters = { 
     "date": {'date': "2015-12-13"}, 
     "name": "Nick", 
     "product": "BT Adapter", 
     "transaction-id": "" 
    } 

    print(magic(parameters)) 


if __name__ == '__main__': 
    main() 
4

Sie missbrauchen die filter Funktion. Das Argument filter ist ein Prädikat, das eine Funktion ist, die einen Wahr/Falsch-Wert zurückgibt, und Filter gibt die Elemente vom zweiten Argument zurück, für das die Funktion true zurückgibt.

Zum Beispiel:

print(list(filter(lambda x: 5, [1,2,3,4,5]))) 
[1, 2, 3, 4, 5] 

Da bool(5) == True Filter gibt alle Elemente.

Da Sie als zweites Argument den Wert parameters.values() übergeben, gibt es keine Möglichkeit, Ihr erwartetes Ergebnis zu erhalten, indem Sie einfach ein Prädikat zum Filtern übergeben.

Was Sie tun möchten, ist so etwas wie:

from itertools import chain 

def listify(value): 
    if isinstance(value, dict): 
     return value.values() 
    elif value: 
     return [value] 
    return() 

print(list(chain.from_iterable(map(listify, parameters.values())))) 

Also zuerst konvertieren Sie die Werte in Sequenzen, und dann verketten Sie sie chain.from_iterable verwenden. Die leeren Werte werden durch listify entfernt, da in diesem Fall eine leere Sequenz zurückgegeben wird. Probelauf:

In [2]: parameters = { 
    ...: "date": {'date':"2015-12-13"}, 
    ...: "name": "Nick", 
    ...: "product": "BT Adapter", 
    ...: "transaction-id": "" 
    ...: } 

In [3]: print(list(chain.from_iterable(map(listify, parameters.values())))) 
['2015-12-13', 'Nick', 'BT Adapter'] 

auch: es macht keinen Sinn, eine komplexe Lambda-Funktion mit verschachtelten Bedingungen zu schreiben, so benutzen Sie einfach ein def und richtig schreiben. lambda s sind nur in Ordnung, wenn sie extrem kurz sind.

2

Es sieht für mich aus, als ob Sie versuchen, eine map Operation mit Ihrer filter, zeigt ein bisschen ein Missverständnis. Die Funktion in einem Filter muss im Wesentlichen zurückkehrt True oder False, um zu bestimmen, ob einen bestimmten Wert im zweiten Argumente zu halten, so dass es nicht sinnvoll auf diese Weise zu filtern machen:

filter(lambda x: x if len(x) > 0 and type(x) is not dict else None, parameters.values()) 

Besser:

filter(lambda x: len(x) > 0 and type(x) is not dict, parameters.values()) 
# better idiom 
filter(lambda x: len(x) > 0 and not isinstance(x, dict), parameters.values()) 

Dies gilt insbesondere für Ihren nächsten Versuch, der versucht, eine Filterfunktion zu mapinnerhalb.Es ist besser, daran zu denken als ein zweistufiger Prozess:

  1. entfernen leere Strings/Listen (alles wo lex(x) < 1)
  2. Get Werte der Wörterbücher

ist dies stattdessen Lassen Sie versuchen, wenn Sie brauchen zu verwenden filter. Ich verwende Python3, was bedeutet, dass ich eine Menge hässliche list Casting zu tun haben:

list(map(lambda x: list(x.values()) if isinstance(x, dict) else x, filter(lambda x: len(x) > 0, parameters.values()))) 

Dies erzeugt:

[['2015-12-13'], 'BT Adapter', 'Nick'] 

Diese gar nicht pythonic ist: filter und map vieles mehr sind zu Hause in Listenkomprehensionen wie folgt aus:

[list(v.values()) if isinstance(v, dict) else v for v in parameters.values() if len(v) > 0] 

Lassen Sie mich wissen, wenn Sie auch die Liste zu glätten nach dem Aufstehen des Wörterbuch Wertes benötigen s.

0

Es ist für das letzte Attribut "Transaktionsnummer", weil seine Länge 0.

ist dies nicht der Fall für Sie arbeiten würde:

print filter(lambda x: x if len(x) >= 0 and type(x) is not dict else map(lambda y: x[y], x.keys()), parameters.values())