简体   繁体   中英

How do I search Values in a dictionary which are lists

I have the following line of code:

food_web = {'Limpets ': [' Seaweed'],'Zooplankton ': ['Phytoplankton'],'Fish':[' Prawn'],'Whelk ': [' Limpets', ' Mussels'],'Lobster ': [' Crab', ' Mussels', ' Limpets', ' Whelk']}

I want to determine an apex predator, which would mean a key that does not appear in any values of the dictionary, so I need to search for each key in all the values but I've got no idea how to approach this.The values are list as well which makes things difficult for me. I am just learning python so my knowledge may well be below par..

I have a concise solution, but it only works if the keys and values are character-for-character identical, so you'll have to strip off the spaces at the beginnings and ends of your strings first.

food_web = {
    'Limpets': ['Seaweed'],
    'Zooplankton': ['Phytoplankton'],
    'Fish': ['Prawn'],
    'Whelk': ['Limpets', 'Mussels'],
    'Lobster': ['Crab', 'Mussels', 'Limpets', 'Whelk']
}

print set(food_web.keys()) - set().union(*food_web.values())

Result:

set(['Zooplankton', 'Fish', 'Lobster'])

A little more explanation: set.union() takes all of its arguments and combines them into one set. The asterisk unpacks the elements of food_web.values() into individual arguments. Subtracting two sets gives a set of all the items in the first set that aren't in the second.

The easiest thing would probably be to combine all of the values into a single list:

values = [item.strip() for subl in food_web.values() for item in subl]

Let's look at this line from the inside out:

food_web.values() is a list of all of the values in the dictionary. So it's a list of lists. I want to extract all of the values inside the inner-lists, so I'm adding another 'comprehension': for item in subl . Together, this takes each of the sub-lists in food_web.values() and extracts each element. It then puts all of those (individual) elements back together into a single list.

I'm using the strip() command to remove the extra whitespace which will make string-comparisons more difficult.

You can then check to see if the items exist in this new list:

for kk in food_web.keys():
    if kk.strip() not in values:
        print("Apex: ", kk)

create a set of all the values, stripping the whitespace and iterate over the keys also stripping and checking if the key is in the set of values:

from itertools import chain
vals = set(s.strip() for s in chain.from_iterable(food_web.values()))


for k in food_web:
    if k.strip() not in vals:
        print(k)

Which outputs:

Lobster 
Zooplankton 
Fish 

If the keys and values did not have extra whitespace you could use dict.viewkeys in python 2 or just .keys in python3:

# food_web.keys()  python3
print(food_web.viewkeys() - chain.from_iterable(food_web.values()))

which would give:

set(['Lobster', 'Zooplankton', 'Fish'])

but that only works for identical strings which yours are not.

If you want to first tidy up your keys and values then viewkeys would work and you will have a more memory efficient solution:

for k,v in food_web.items():
    food_web[k] = [x.strip() for x in v]

print(food_web.viewkeys() - chain.from_iterable(food_web.values())) 
[key1 for key1 in food_web if not any([key1 in value for key2, value in food_web.items()])]

the following is a nested comprehension. The presence of keys from the outer comprehension is being checked in the inner one. This returns the list of booleans. Evaluating the any function on this list returns true, only if any of the elements in the list is true. Therefore this expression returns the collection of keys none of which are present in the values of the given dictionary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM