Matching lists when elements are not ordered - python

let's say I have a list b=['m','NN'] and a dictionary dict={'b':['NN','m','big']} and I want to use the function to retrieve the key 'b' if the elements of the list b are in dict[b]
(so let's say using [k for k,v in dict.items()].
Now how do I do that if the elements in b are not ordered as the elements in dict[b] and supposing I cannot change the order in the b list?
Thank you!

Not certain I understand what you're asking, but if what you're after is the list of keys in dictionary d with values which are super-sets of the list b, you could use something like:
b=['m','NN']
d={'b':['NN','m','big'], 'a':['jj','r']}
[k for k,v in d.items() if set(b) <= set(v)]
(I changed the name of your example dictionary as dict is a built-in class.)

You can do:
[k for k, v in dict.items() if all((x in v) for x in b)]
For example:
>>> b=['m','NN']
>>> dict={'b':['NN','m','big'], 'a':['NN', 'q']}
>>> [k for k, v in dict.items() if all((x in v) for x in b)]
['b']
(Note that it is a bad idea to name your dictionary dict, since dict is the name of the data type).

Related

Python: How do you determine if a list of unordered tuples is IN a dictionaries.values()?

Im trying to iterate through one dictionary and determine if during iteration the value is present in a second dictionary. The values are lists with tuple coordinates at list items. When I run the following expected results don't return. What could I be doing wrong?
o={123:[(2045414.2025330812, 737011.67879535258), (2045345.5412850082, 736965.27060331404)]}
t={234:[(2053962.2499010414, 731325.2501180619), (2053955.6251330376, 731121.18739786744)]}
y={345:[(2045414.2025330812, 737011.67879535258), (2045345.5412850082, 736965.27060331404)]}
h={456:[(2045345.5412850082, 736965.27060331404), (2045414.2025330812, 737011.67879535258)]}
for k, v in o.items():
if v in h.values():
print k, v
If you mean that the list of tuples is itself unordered, then perhaps that is the problem in that you are comparing v to something in h.values(), but where h.values() has the list in a different order. Why not simply store sets as the values?
checker = set(list(map(set, h.values))
for k, v in o.items():
if set(v) in checker:
print(k,v)
Perhaps you can create your data structures in this format to avoid the unnecessary overhead.
You are comparing an ordered list of tuples. To compare an unordered collection of tuples, you can use set:
for k, v in o.items():
if set(v).issubset(set(next(iter(h.values())))):
print(k, v)
123 [(2045414.2025330812, 737011.6787953526), (2045345.5412850082, 736965.270603314)]
An alternative way of writing the above logic:
for k, v in o.items():
if set(v) <= set(list(h.values())[0]):
print(k, v)
The tricky part is converting dict.values() to a set. Since h only has one value, you need to extract the only value before conversion to set.

Find non-Empty value in dict

I have a dict like this:
d = {'first':'', 'second':'', 'third':'value', 'fourth':''}
and I want to find first non-empty value (and it's name, in this example 'third'). There may be more than one non-empty value, but I only want the first one I find.
How can I do this?
Use an OrderedDict which preserves the order of elements. Then loop over them and find the first that isn't empty:
from collections import OrderedDict
d = OrderedDict()
# fill d
for key, value in d.items():
if value:
print(key, " is not empty!")
You could use next (dictionaries are unordered - this somewhat changed in Python 3.6 but that's only an implementation detail currently) to get one "not-empty" key-value pair:
>>> next((k, v) for k, v in d.items() if v)
('third', 'value')
Like this?
def none_empty_finder(dict):
for e in dict:
if dict[e] != '':
return [e,dict[e]]
d = {'first':'', 'second':'', 'third':'value', 'fourth':''}
for k, v in d.items():
if v!='':
return k, v
Edit 1
from the comment if the value is None or '' we better use if v: instead of if v!=''. if v!='' only check the '' and skip others
You can find empty elements and make a list of them:
non_empty_list = [(k,v) for k,v in a.items() if v]
By using list comprehension, you can list all the non-empty values and then fetch the 0th value:
[val for key, val in d.items() if val][0]

Sum up values from a dictionary (the Python way)

Given the following dictionary, let's call it mydict
{'Plekhg2': {'Bcells': '233.55', 'DendriticCells': '190.12'},
'Barxxxx': {'Bcells': '132.11', 'DendriticCells': '92.01'}, }
I want to sum up values for each key from inner dictionary, resulting in:
{'Plekhg2': 423.67, # 233.55 + 190.12
'Barxxxx': 224.12} # 132.11 + 92.01
How can I achieve that with Python idiom?
With a dict comprehension, using sum() to sum the nested dictionary values; Python 2.6 or before would use dict() and a generator expression:
# Python 2.7
{k: sum(float(f) for f in v.itervalues()) for k, v in mydict.iteritems()}
# Python 3.x
{k: sum(map(float, v.values())) for k, v in mydict.items()}
# Python 2.6 and before
dict((k, sum(float(f) for f in v.values())) for k, v in mydict.iteritems())
You may want to store float values to begin with though.
Demo:
>>> mydict ={'Plekhg2': {'Bcells': '233.55', 'DendriticCells': '190.12'},
... 'Barxxxx': {'Bcells': '132.11', 'DendriticCells': '92.01'}, }
>>> {k: sum(float(f) for f in v.itervalues()) for k, v in mydict.iteritems()}
{'Plekhg2': 423.67, 'Barxxxx': 224.12}
Use a dict comprehension and sum, since the values are strings you'll have to convert them to floats first using float.
>>> {k:sum(float(x) for x in v.itervalues()) for k, v in d.iteritems()}
{'Plekhg2': 423.67, 'Barxxxx': 224.12}
For Python 3 use .items() and .values() instead of the .iter(values|items).
Just for completion in Python 3:
In [134]:
{k:sum(float(x) for x in v.values()) for k, v in my_dict.items()}
Out[134]:
{'Barxxxx': 224.12, 'Plekhg2': 423.67}

Selecting elements of a Python dictionary greater than a certain value

I need to select elements of a dictionary of a certain value or greater. I am aware of how to do this with lists, Return list of items in list greater than some value.
But I am not sure how to translate that into something functional for a dictionary. I managed to get the tags that correspond (I think) to values greater than or equal to a number, but using the following gives only the tags:
[i for i in dict if dict.values() >= x]
.items() will return (key, value) pairs that you can use to reconstruct a filtered dict using a list comprehension that is feed into the dict() constructor, that will accept an iterable of (key, value) tuples aka. our list comprehension:
>>> d = dict(a=1, b=10, c=30, d=2)
>>> d
{'a': 1, 'c': 30, 'b': 10, 'd': 2}
>>> d = dict((k, v) for k, v in d.items() if v >= 10)
>>> d
{'c': 30, 'b': 10}
If you don't care about running your code on python older than version 2.7, see #opatut answer using "dict comprehensions":
{k:v for (k,v) in dict.items() if v > something}
While nmaier's solution would have been my way to go, notice that since python 2.7+ there has been a "dict comprehension" syntax:
{k:v for (k,v) in dict.items() if v > something}
Found here: Create a dictionary with list comprehension in Python. I found this by googling "python dictionary list comprehension", top post.
Explanation
{ .... } includes the dict comprehension
k:v what elements to add to the dict
for (k,v) in dict.items() this iterates over all tuples (key-value-pairs) of the dict
if v > something a condition that has to apply on every value that is to be included
You want dict[i] not dict.values(). dict.values() will return the whole list of values that are in the dictionary.
dict = {2:5, 6:2}
x = 4
print [dict[i] for i in dict if dict[i] >= x] # prints [5]

efficiently swap a python dict's keys and values where the values contain one or more elements

Suppose I have a dict:
x = { "a": ["walk", "the", "dog"], "b": ["dog", "spot"], "c":["the", "spot"] }
and want to have the new dict:
y = { "walk": ["a"], "the": ["a", "c"], "dog":["a", "b"], "spot":["b","c"] }
What is the most efficient way to do this? If a solution is a few lines and is somehow made simple by a pythonic construct what is it (even if it's not most efficient)?
Note that this is different than other questions where the value is a single element and not a list.
You can use defaultdict:
from collections import defaultdict
y = defaultdict(list)
for key, values in x.items(): # .iteritems() in Python 2
for value in values:
y[value].append(key)
y = {}
for (k, v) in x.iteritems():
for e in v:
y.setdefault(e, []).append(k)
I presented this as an alternative to #Blender's answer, since it's what I'm accustomed to using, but I think Blender's is superior since it avoids constructing a temporary [] on every pass of the inner loop.
Not necessarily efficient, but a one liner just for fun:
{b: [k for k, w in x.iteritems() if b in w] for v in x.values() for b in v}
The idea here is to iterate over all the values in the original dictionary (for v in x.values()), then iterate over all the items in the list (for b in v), then use b as the key in a dict-comprehension. The value for b is a list comprehension [k for ...] where the members are the keys in dictionary x for which the value w contains the word b.
Because the scope is limited you can actually write v instead of w above, which makes it even harder to understand. :-)
(Edit to add, I'd use #Blender's. These one liners are fun, but really hard to grok.)

Categories

Resources