Abrufen einer Werteliste aus einer Liste von Diktaten


184

Ich habe eine Liste solcher Diktate:

[{'value': 'apple', 'blah': 2}, 
 {'value': 'banana', 'blah': 3} , 
 {'value': 'cars', 'blah': 4}]

Ich will ['apple', 'banana', 'cars']

Was ist der beste Weg, dies zu tun?

Antworten:


324

Angenommen, jedes Diktat hat einen valueSchlüssel, können Sie schreiben (vorausgesetzt, Ihre Liste heißt benannt l).

[d['value'] for d in l]

Wenn valuemöglicherweise fehlt, können Sie verwenden

[d['value'] for d in l if 'value' in d]

8
Um fehlende Werte für einen Schlüssel zu behandeln, kann man auch d.get ("key_to_lookup", "alternative_value") verwenden. Dann sieht es so aus: [d.get ('value', 'alt') für d in l]. Wenn der Wert nicht als Schlüssel vorhanden ist, wird einfach 'alt' zurückgegeben.
Abhinav

Vielen Dank für die Lösung
Ajay Kumar

Diese "Magie" ist bekannt als Listenverständnis docs.python.org/3/tutorial/…
William Ardila

34

Hier ist eine andere Möglichkeit, dies mit den Funktionen map () und lambda zu tun:

>>> map(lambda d: d['value'], l)

wo l ist die Liste. Ich sehe diesen Weg "sexiest", aber ich würde es mit dem Listenverständnis tun.

Update: Falls dieser 'Wert' als Schlüssel fehlt, verwenden Sie:

>>> map(lambda d: d.get('value', 'default value'), l)

Update: Ich bin auch kein großer Fan von Lambdas, ich nenne lieber Dinge ... so würde ich es in diesem Sinne machen:

>>> import operator
>>> map(operator.itemgetter('value'), l)

Ich würde sogar noch weiter gehen und eine einzige Funktion erstellen, die explizit sagt, was ich erreichen möchte:

>>> import operator, functools
>>> get_values = functools.partial(map, operator.itemgetter('value'))
>>> get_values(l)
... [<list of values>]

mapVerwenden Sie listin Python 3, da ein Iterator zurückgegeben wird , um eine Liste zurückzugeben, z list(map(operator.itemgetter('value'), l)).


1
Brutto! Das Listenverständnis macht hier viel mehr Sinn.
Mike Graham

4
Wenn Sie die erste verwenden mapmöchten operator.itemgetter('value'), verwenden Sie nicht a lambda.
Agf

18
[x['value'] for x in list_of_dicts]

oder [d.getkey ('value') für d in dict_list]
rplnt

1
@rpInt Ähm, es gibt keine getkey... meinst du d.get('value')? Das wäre dasselbe wie @ isbadawis 2. Listenverständnis, nicht das von Michal.
Agf

3
Ja, sorry, ich wollte bekommen. Und ich meinte es als etwas, das keine Ausnahme auslöst, wenn der Schlüssel fehlt. Die Lösung von @ isbadawi ist jedoch besser, da get () None (oder was auch immer wir als Standard angeben) liefert, wenn der Schlüssel fehlt.
rplnt

5

Für einen sehr einfachen Fall wie diesen ist ein Verständnis wie in Ismail Badawis Antwort definitiv der richtige Weg.

Wenn die Dinge jedoch komplizierter werden und Sie mit dem Schreiben von Mehrklauseln oder verschachtelten Verständnissen mit komplexen Ausdrücken beginnen müssen, sollten Sie nach anderen Alternativen suchen. Es gibt verschiedene (quasi) Standardmethoden zum Festlegen von XPath-Suchvorgängen in verschachtelten Diktat- und Listenstrukturen wie JSONPath, DPath und KVC. Und es gibt nette Bibliotheken auf PyPI für sie.

Hier ist ein Beispiel mit der genannten Bibliothek dpath, das zeigt, wie es etwas etwas komplizierteres vereinfachen kann:

>>> dd = {
...     'fruits': [{'value': 'apple', 'blah': 2}, {'value': 'banana', 'blah': 3}],
...     'vehicles': [{'value': 'cars', 'blah':4}]}

>>> {key: [{'value': d['value']} for d in value] for key, value in dd.items()}
{'fruits': [{'value': 'apple'}, {'value': 'banana'}],
 'vehicles': [{'value': 'cars'}]}

>>> dpath.util.search(dd, '*/*/value')
{'fruits': [{'value': 'apple'}, {'value': 'banana'}],
 'vehicles': [{'value': 'cars'}]}

Oder mit jsonpath-ng:

>>> [d['value'] for key, value in dd.items() for d in value]
['apple', 'banana', 'cars']
>>> [m.value for m in jsonpath_ng.parse('*.[*].value').find(dd)]
['apple', 'banana', 'cars']

Dieser sieht auf den ersten Blick möglicherweise nicht ganz so einfach aus, da findÜbereinstimmungsobjekte zurückgegeben werden, die alle Arten von Dingen außer nur dem übereinstimmenden Wert enthalten, z. B. einen Pfad direkt zu jedem Element. Bei komplexeren Ausdrücken kann es jedoch einen großen Unterschied machen , einen Pfad wie '*.[*].value'anstelle einer Verständnisklausel für jeden anzugeben *. Außerdem ist JSONPath eine sprachunabhängige Spezifikation, und es gibt sogar Online-Tester , die beim Debuggen sehr praktisch sein können.


1

Ich denke, so einfach wie unten würde Ihnen geben, wonach Sie suchen.

In[5]: ll = [{'value': 'apple', 'blah': 2}, {'value': 'banana', 'blah': 3} , {'value': 'cars', 'blah':4}]
In[6]: ld = [d.get('value', None) for d in ll]
In[7]: ld
Out[7]: ['apple', 'banana', 'cars']

Sie können dies auch mit einer Kombination aus mapund tun, lambdaaber das Listenverständnis sieht eleganter und pythonischer aus.

Für eine kleinere Eingabeliste ist das Verständnis ein guter Weg, aber wenn die Eingabe wirklich groß ist, sind Generatoren meiner Meinung nach der ideale Weg.

In[11]: gd = (d.get('value', None) for d in ll)
In[12]: gd
Out[12]: <generator object <genexpr> at 0x7f5774568b10>
In[13]: '-'.join(gd)
Out[13]: 'apple-banana-cars'

Hier ist ein Vergleich aller möglichen Lösungen für größere Eingaben

 In[2]: l = [{'value': 'apple', 'blah': 2}, {'value': 'banana', 'blah': 3} , {'value': 'cars', 'blah':4}] * 9000000
In[3]: def gen_version():
  ...:     for i in l:
  ...:         yield i.get('value', None)
  ...: 
In[4]: def list_comp_verison():
  ...:     return [i.get('value', None) for i in l]
  ...: 
In[5]: def list_verison():
  ...:     ll = []
  ...:     for i in l:
  ...:         ll.append(i.get('value', None))
  ...:     return ll
In[10]: def map_lambda_version():
   ...:      m = map(lambda i:i.get('value', None), l)
   ...:      return m
   ...: 
In[11]: %timeit gen_version()
172 ns ± 0.393 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In[12]: %timeit map_lambda_version()
203 ns ± 2.31 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In[13]: %timeit list_comp_verison()
1.61 s ± 20.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In[14]: %timeit list_verison()
2.29 s ± 4.58 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Wie Sie sehen können, sind Generatoren im Vergleich zu den anderen eine bessere Lösung. Die Karte ist im Vergleich zum Generator auch langsamer, da ich es dem OP überlassen werde, dies herauszufinden.


1

Folge dem Beispiel --

songs = [
{"title": "happy birthday", "playcount": 4},
{"title": "AC/DC", "playcount": 2},
{"title": "Billie Jean", "playcount": 6},
{"title": "Human Touch", "playcount": 3}
]

print("===========================")
print(f'Songs --> {songs} \n')
title = list(map(lambda x : x['title'], songs))
print(f'Print Title --> {title}')

playcount = list(map(lambda x : x['playcount'], songs))
print(f'Print Playcount --> {playcount}')
print (f'Print Sorted playcount --> {sorted(playcount)}')

# Aliter -
print(sorted(list(map(lambda x: x['playcount'],songs))))

1

Schlüsselwerte aus der Liste der Wörterbücher in Python abrufen?

  1. Schlüsselwerte aus der Liste der Wörterbücher in Python abrufen?

Ex:

data = 
[{'obj1':[{'cpu_percentage':'15%','ram':3,'memory_percentage':'66%'}]},
{'obj2': [{'cpu_percentage':'0','ram':4,'memory_percentage':'35%'}]}]

für d in Daten:

  for key,value in d.items(): 

      z ={key: {'cpu_percentage': d['cpu_percentage'],'memory_percentage': d['memory_percentage']} for d in value} 
      print(z)

Ausgabe:

{'obj1': {'cpu_percentage': '15%', 'memory_percentage': '66%'}}
{'obj2': {'cpu_percentage': '0', 'memory_percentage': '35%'}}

-2

Ein sehr einfacher Weg, dies zu tun, ist:

list1=['']
j=0
for i in com_list:
    if j==0:
        list1[0]=(i['value'])
    else:
        list1.append(i['value'])
    j+=1

Ausgabe:

['Apfel', 'Banane', 'Autos']

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.