Get all values from nested dictionaries in python - python

I have some dictionaries of dictionaries, like this:
a['b']['c']['d']['answer'] = answer1
a['b']['c']['e']['answer'] = answer2
a['b']['c']['f']['answer'] = answer3
....
a['b']['c']['d']['conf'] = conf1
a['b']['c']['e']['conf'] = conf2
a['b']['c']['f']['conf'] = conf3
Is there a fast way to get a list of values of all answers for all elements at the third level (d,e,f)?
Specifically I'd like to know if there's any mechanism implementing a wildcard (e.g., a['b']['c']['*']['answer'].values()
update
The fastest way I've found till now is:
[x['answer'] for x in a['b']['c'].values()]

In Python3 we can build a simple generator for this:
def NestedDictValues(d):
for v in d.values():
if isinstance(v, dict):
yield from NestedDictValues(v)
else:
yield v
a={4:1,6:2,7:{8:3,9:4,5:{10:5},2:6,6:{2:7,1:8}}}
list(NestedDictValues(a))
The output is:
[1, 2, 3, 4, 6, 5, 8, 7]
which is all of the values.

You could use a simple list comprehension:
[a['b']['c'][key]['answer'] for key in a['b']['c'].keys()]
Out[11]: ['answer1', 'answer2', 'answer3']
If you want to get all the answers and conf etc. You could do:
[[a['b']['c'][key][type] for key in a['b']['c'].keys()] for type in a['b']['c']['d'].keys()]
Out[15]: [['conf1', 'conf2', 'conf3'], ['answer1', 'answer2', 'answer3']]

I would do that using recursive generator function:
def d_values(d, depth):
if depth == 1:
for i in d.values():
yield i
else:
for v in d.values():
if isinstance(v, dict):
for i in d_values(v, depth-1):
yield i
Example:
>>> list(d_values({1: {2: 3, 4: 5}}, 2))
[3, 5]
In your case, this would give a dictionary like {'answer': answer1, 'conf': conf1} as each item, so you can use:
list(d['answer'] for d in d_values(a, 3))

Just to give an answer to this topic, copying my solution from the "updating status" of my question:
[x['answer'] for x in a['b']['c'].values()]
Hope this can help.

list(map(lambda key: a['b']['c'][key], a['b']['c'].keys()))

You can use a NestedDict. First, let me recreate your dictionary
>>> from ndicts.ndicts import NestedDict
>>> nd = NestedDict.from_product("b", "c", "def", ["answer", "conf"])
NestedDict({
'b': {
'c': {
'd': {'answer': None, 'conf': None},
'e': {'answer': None, 'conf': None},
'f': {'answer': None, 'conf': None}
}
}
})
Then use an empty string as a wildcard
>>> nd_extract = nd.extract["b", "c", "", "answer"]
>>> nd_extract
NestedDict({
'b': {
'c': {
'd': {'answer': None},
'e': {'answer': None},
'f': {'answer': None}
}
}
})
Finally get the values
>>> list(nd_extract.values())
[None, None, None]
To install ndicts
pip install ndicts

Related

How can I add n times a value in a dictionary? [duplicate]

Can I use list comprehension syntax to create a dictionary?
For example, by iterating over pairs of keys and values:
d = {... for k, v in zip(keys, values)}
Use a dict comprehension (Python 2.7 and later):
{key: value for (key, value) in iterable}
Alternatively for simpler cases or earlier version of Python, use the dict constructor, e.g.:
pairs = [('a', 1), ('b', 2)]
dict(pairs) #=> {'a': 1, 'b': 2}
dict([(k, v+1) for k, v in pairs]) #=> {'a': 2, 'b': 3}
Given separate arrays of keys and values, use the dict constructor with zip:
keys = ['a', 'b']
values = [1, 2]
dict(zip(keys, values)) #=> {'a': 1, 'b': 2}
2) "zip'ped" from two separate iterables of keys/vals
dict(zip(list_of_keys, list_of_values))
In Python 3 and Python 2.7+, dictionary comprehensions look like the below:
d = {k:v for k, v in iterable}
For Python 2.6 or earlier, see fortran's answer.
In fact, you don't even need to iterate over the iterable if it already comprehends some kind of mapping, the dict constructor doing it graciously for you:
>>> ts = [(1, 2), (3, 4), (5, 6)]
>>> dict(ts)
{1: 2, 3: 4, 5: 6}
>>> gen = ((i, i+1) for i in range(1, 6, 2))
>>> gen
<generator object <genexpr> at 0xb7201c5c>
>>> dict(gen)
{1: 2, 3: 4, 5: 6}
Create a dictionary with list comprehension in Python
I like the Python list comprehension syntax.
Can it be used to create dictionaries too? For example, by iterating
over pairs of keys and values:
mydict = {(k,v) for (k,v) in blah blah blah}
You're looking for the phrase "dict comprehension" - it's actually:
mydict = {k: v for k, v in iterable}
Assuming blah blah blah is an iterable of two-tuples - you're so close. Let's create some "blahs" like that:
blahs = [('blah0', 'blah'), ('blah1', 'blah'), ('blah2', 'blah'), ('blah3', 'blah')]
Dict comprehension syntax:
Now the syntax here is the mapping part. What makes this a dict comprehension instead of a set comprehension (which is what your pseudo-code approximates) is the colon, : like below:
mydict = {k: v for k, v in blahs}
And we see that it worked, and should retain insertion order as-of Python 3.7:
>>> mydict
{'blah0': 'blah', 'blah1': 'blah', 'blah2': 'blah', 'blah3': 'blah'}
In Python 2 and up to 3.6, order was not guaranteed:
>>> mydict
{'blah0': 'blah', 'blah1': 'blah', 'blah3': 'blah', 'blah2': 'blah'}
Adding a Filter:
All comprehensions feature a mapping component and a filtering component that you can provide with arbitrary expressions.
So you can add a filter part to the end:
>>> mydict = {k: v for k, v in blahs if not int(k[-1]) % 2}
>>> mydict
{'blah0': 'blah', 'blah2': 'blah'}
Here we are just testing for if the last character is divisible by 2 to filter out data before mapping the keys and values.
In Python 2.7, it goes like:
>>> list1, list2 = ['a', 'b', 'c'], [1,2,3]
>>> dict( zip( list1, list2))
{'a': 1, 'c': 3, 'b': 2}
Zip them!
Python version >= 2.7, do the below:
d = {i: True for i in [1,2,3]}
Python version < 2.7(RIP, 3 July 2010 - 31 December 2019), do the below:
d = dict((i,True) for i in [1,2,3])
To add onto #fortran's answer, if you want to iterate over a list of keys key_list as well as a list of values value_list:
d = dict((key, value) for (key, value) in zip(key_list, value_list))
or
d = {(key, value) for (key, value) in zip(key_list, value_list)}
Just to throw in another example. Imagine you have the following list:
nums = [4,2,2,1,3]
and you want to turn it into a dict where the key is the index and value is the element in the list. You can do so with the following line of code:
{index:nums[index] for index in range(0,len(nums))}
Here is another example of dictionary creation using dict comprehension:
What i am tring to do here is to create a alphabet dictionary where each pair; is the english letter and its corresponding position in english alphabet
>>> import string
>>> dict1 = {value: (int(key) + 1) for key, value in
enumerate(list(string.ascii_lowercase))}
>>> dict1
{'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4, 'g': 7, 'f': 6, 'i': 9, 'h': 8,
'k': 11, 'j': 10, 'm': 13, 'l': 12, 'o': 15, 'n': 14, 'q': 17, 'p': 16, 's':
19, 'r': 18, 'u': 21, 't': 20, 'w': 23, 'v': 22, 'y': 25, 'x': 24, 'z': 26}
>>>
Notice the use of enumerate here to get a list of alphabets and their indexes in the list and swapping the alphabets and indices to generate the key value pair for dictionary
Hope it gives a good idea of dictionary comp to you and encourages you to use it more often to make your code compact
This code will create dictionary using list comprehension for multiple lists with different values that can be used for pd.DataFrame()
#Multiple lists
model=['A', 'B', 'C', 'D']
launched=[1983,1984,1984,1984]
discontinued=[1986, 1985, 1984, 1986]
#Dictionary with list comprehension
keys=['model','launched','discontinued']
vals=[model, launched,discontinued]
data = {key:vals[n] for n, key in enumerate(keys)}
#Convert dict to dataframe
df=pd.DataFrame(data)
display(df)
enumerate will pass n to vals to match each key with its list
Try this,
def get_dic_from_two_lists(keys, values):
return { keys[i] : values[i] for i in range(len(keys)) }
Assume we have two lists country and capital
country = ['India', 'Pakistan', 'China']
capital = ['New Delhi', 'Islamabad', 'Beijing']
Then create dictionary from the two lists:
print get_dic_from_two_lists(country, capital)
The output is like this,
{'Pakistan': 'Islamabad', 'China': 'Beijing', 'India': 'New Delhi'}
Adding to #Ekhtiar answer, if you want to make look up dict from list, you can use this:
names = ['a', 'b', 'd', 'f', 'c']
names_to_id = {v:k for k, v in enumerate(names)}
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'f': 4}
Or in rare case that you want to filter duplicate, use set first (best in list of number):
names = ['a', 'b', 'd', 'f', 'd', 'c']
sorted_list = list(set(names))
sorted_list.sort()
names_to_id = {v:k for k, v in enumerate(sorted_list)}
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'f': 4}
names = [1,2,5,5,6,2,1]
names_to_id = {v:k for k, v in enumerate(set(names))}
# {1: 0, 2: 1, 5: 2, 6: 3}
>>> {k: v**3 for (k, v) in zip(string.ascii_lowercase, range(26))}
Python supports dict comprehensions, which allow you to express the creation of dictionaries at runtime using a similarly concise syntax.
A dictionary comprehension takes the form {key: value for (key, value) in iterable}. This syntax was introduced in Python 3 and backported as far as Python 2.7, so you should be able to use it regardless of which version of Python you have installed.
A canonical example is taking two lists and creating a dictionary where the item at each position in the first list becomes a key and the item at the corresponding position in the second list becomes the value.
The zip function used inside this comprehension returns an iterator of tuples, where each element in the tuple is taken from the same position in each of the input iterables. In the example above, the returned iterator contains the tuples (“a”, 1), (“b”, 2), etc.
Output:
{'i': 512, 'e': 64, 'o': 2744, 'h': 343, 'l': 1331, 's': 5832, 'b': 1, 'w': 10648, 'c': 8, 'x': 12167, 'y': 13824, 't': 6859, 'p': 3375, 'd': 27, 'j': 729, 'a': 0, 'z': 15625, 'f': 125, 'q': 4096, 'u': 8000, 'n': 2197, 'm': 1728, 'r': 4913, 'k': 1000, 'g': 216, 'v': 9261}
Yes, it's possible. In python, Comprehension can be used in List, Set, Dictionary, etc.
You can write it this way
mydict = {k:v for (k,v) in blah}
Another detailed example of Dictionary Comprehension with the Conditional Statement and Loop:
parents = [father, mother]
parents = {parent:1 - P["mutation"] if parent in two_genes else 0.5 if parent in one_gene else P["mutation"] for parent in parents}
You can create a new dict for each pair and merge it with the previous dict:
reduce(lambda p, q: {**p, **{q[0]: q[1]}}, bla bla bla, {})
Obviously this approaches requires reduce from functools.
Assuming blah blah blah is a two-tuples list:
Let's see two methods:
# method 1
>>> lst = [('a', 2), ('b', 4), ('c', 6)]
>>> dict(lst)
{'a': 2, 'b': 4, 'c': 6}
# method 2
>>> lst = [('a', 2), ('b', 4), ('c', 6)]
>>> d = {k:v for k, v in lst}
>>> d
{'a': 2, 'b': 4, 'c': 6}
this approach uses iteration over the given date using a for loop.
Syntax: {key: value for (key, value) in data}
Eg:
# create a list comprehension with country and code:
Country_code = [('China', 86), ('USA', 1),
('Ghana', 233), ('Uk', 44)]
# use iterable method to show results
{key: value for (key, value) in Country_code}

One-liner for updating a value in a list of dictionaries - Python

I have a list of dictionaries like so:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
I would like to do something similar to the following so that each of the numbers which are the value pair for the "integer" key are returned as integers:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
r = map(lambda x: x["integer"]=int(x["integer"]), l)
print r
#[{"integer":1},{"integer":2},{"integer":3},{"integer":4}]
But this causes an error:
SyntaxError: lambda cannot contain assignment
Does anyone know of a clean way to do this in python? Preferably a oneliner using map or something similar?
Use a list comprehension comprehension
You will iterate through the dictionaries in the list and have them returned as x, then insert a new dictionary with your desired key and the integer value of the return within a new list
r = [{'integer': int(x['integer'])} for x in l]
You should just use a loop:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
for d in l:
d["integer"] = int(d["integer"])
print(l)
#[{'integer': 1}, {'integer': 2}, {'integer': 3}, {'integer': 4}]
However, here is a one-liner that should work for you:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
[d.update({"integer": int(d["integer"])}) for d in l]
print(l)
#[{'integer': 1}, {'integer': 2}, {'integer': 3}, {'integer': 4}]
Be aware that dict.update() returns None, so if you assigned the output of the list comprehension to a variable it would be a list containing all Nones.
print([d.update({"integer": int(d["integer"])}) for d in l])
#[None, None, None, None]
The following works in one line:
r = [{'integer':int(x['integer'])} for x in l]
print(r)
# [{'integer': 1}, {'integer': 2}, {'integer': 3}, {'integer': 4}]
This utilizes a dict comprehension inside a list comprehension.
[i.update({w:int(k)}) for i in l for w,k in i.items()]
it the second loop is only looping over one key set, so take the two loops with gram of salt :)
Awesome solution by one of my friends in a chat:
>>> listOfDict = [{1:1338}, {1:1338}, {1:1338}]
>>> y = 1337
>>> value = 1
>>> map(lambda x: x.update({value: y}), listOfDict)
[None, None, None]
>>> listOfDict
[{1: 1337}, {1: 1337}, {1: 1337}]
You can try the following
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
a = [dict(d, **{'abcd':5}) for d in l]
print(a)
[{'integer': '1', 'abcd': 4}, {'integer': '2', 'abcd': 4}, {'integer': '3', 'abcd': 4}, {'integer': '4', 'abcd': 4}]

Remove dict element from list of dicts using lambda

New to python here:
I'm trying to create a new list where every dict from initial list has an element removed, it exists:
arraylist = [{"x":1, "y":2}, {"x":3, "y":2}, {"x":5, "y":2}, {"x":33, "y":2}, {"x":1, "y":8}]
arraylist = map(lambda d: del d["y"] if "y" in d, arraylist)
I know I can do it using for, using del. But I'm looking to learn something new.
Use a list comprehension:
In [26]: [{x:d[x] for x in d if x != 'y'} for d in arraylist]
Out[26]: [{'x': 1}, {'x': 3}, {'x': 5}, {'x': 33}, {'x': 1}]
You can use filter like this
arraylist = [{"x":1, "y":2}, {"x":3, "y":2}, {"x":5, "y":2}, {"x":33, "y":2}, {"x":1, "y":8}]
arraylist = map(lambda d: dict(filter(lambda (k,v): k != "y", d.iteritems())), arraylist)
You can't use del in a lambda function because del is a statement and a lambda's body can only be a single expression. You can't put a statement inside an expression. You could make it work with an ordinary function:
def delete_y(d):
if "y" in d:
del d['y']
return d
Note that using del like this modifies the dictionary d in place. This means that returning the modified dictionary (and using the return value to build a new list) is sort of redundant. The original data structure the dictionary came from will already have the modified version.
Maybe its not the shortest way, but it is definitely a convenient way to remove
items from a list:
arraylist = [{"x":1, "y":2}, {"x":3, "y":2}, {"x":5, "y":2}, {"x":33, "y":2}, {"x":1, "y":8}]
print arraylist
def containsY(d):
if 'y' in d.keys():
del d['y']
return True
return False
filter(containsY, arraylist)
print arraylist
output:
[{'y': 2, 'x': 1}, {'y': 2, 'x': 3}, {'y': 2, 'x': 5}, {'y': 2, 'x': 33}, {'y': 8, 'x': 1}]
[{'x': 1}, {'x': 3}, {'x': 5}, {'x': 33}, {'x': 1}]

Group/Count list of dictionaries based on value

I've got a list of Tokens which looks something like:
[{
Value: "Blah",
StartOffset: 0,
EndOffset: 4
}, ... ]
What I want to do is get a count of how many times each value occurs in the list of tokens.
In VB.Net I'd do something like...
Tokens = Tokens.
GroupBy(Function(x) x.Value).
Select(Function(g) New With {
.Value = g.Key,
.Count = g.Count})
What's the equivalent in Python?
IIUC, you can use collections.Counter:
>>> from collections import Counter
>>> tokens = [{"Value": "Blah", "SO": 0}, {"Value": "zoom", "SO": 5}, {"Value": "Blah", "SO": 2}, {"Value": "Blah", "SO": 3}]
>>> Counter(tok['Value'] for tok in tokens)
Counter({'Blah': 3, 'zoom': 1})
if you only need a count. If you want them grouped by the value, you could use itertools.groupby and something like:
>>> from itertools import groupby
>>> def keyfn(x):
return x['Value']
...
>>> [(k, list(g)) for k,g in groupby(sorted(tokens, key=keyfn), keyfn)]
[('Blah', [{'SO': 0, 'Value': 'Blah'}, {'SO': 2, 'Value': 'Blah'}, {'SO': 3, 'Value': 'Blah'}]), ('zoom', [{'SO': 5, 'Value': 'zoom'}])]
although it's a little trickier because groupby requires the grouped terms to be contiguous, and so you have to sort by the key first.
Let's assume that is your python list, containing dictionnaries:
my_list = [{'Value': 'Blah',
'StartOffset': 0,
'EndOffset': 4},
{'Value': 'oqwij',
'StartOffset': 13,
'EndOffset': 98},
{'Value': 'Blah',
'StartOffset': 6,
'EndOffset': 18}]
A one liner:
len([i for i in a if i['Value'] == 'Blah']) # returns 2
import collections
# example token list
tokens = [{'Value':'Blah', 'Start':0}, {'Value':'BlahBlah'}]
count=collections.Counter([d['Value'] for d in tokens])
print count
shows
Counter({'BlahBlah': 1, 'Blah': 1})
token = [{
'Value': "Blah",
'StartOffset': 0,
'EndOffset': 4
}, ... ]
value_counter = {}
for t in token:
v = t['Value']
if v not in value_counter:
value_counter[v] = 0
value_counter[v] += 1
print value_counter
Another efficient way is to convert data to Pandas DataFrame and then aggregate them. Like this:
import pandas as pd
df = pd.DataFrame(data)
df.groupby('key')['value'].count()
df.groupby('key')['value'].sum()

Making unique list in python

What is the most pythonic way of making a list unique using custom equality operator?
For instance you have a list of dicts L, and you want a new list M such that for all dicts d, e in M and one specific x
d[x] != e[x]
How can this be done?
In your case (and all cases where equivalence boils down to the equivalence of some kind of key), you can simply construct a dictionary, where the keys are the values you want to compare:
L = [{'key': 'foo', 'v': 42}, {'key': 'bar', 'v': 43}, {'key': 'foo', 'v': 44}]
x = 'key'
M = {d[x]:d for d in L}.values()
# In old Python versions: dict((d[x],d for d in L)).values()
Note that the result is not deterministic, both
[{'key': 'foo', 'v': 44}, {'key': 'bar', 'v': 43}]
and
[{'key': 'foo', 'v': 42}, {'key': 'bar', 'v': 43}]
are valid results.
In the general case, simply check all accepted values:
def unique(iterable, is_eq):
tmp = []
for el in iterable:
if not any(is_eq(inTmp, el) for inTmp in tmp):
tmp.append(is_eq)
return tmp
Note that this means that your comparison function will be called O(n²) times instead of n times.
Based on FUD's comment to phihag. Note that key function must return a hashable value.
def unique(iterable, key=lambda x : x):
seen = set()
res = []
for item in iterable:
k = key(item)
if k not in seen:
res.append(item)
seen.add(k)
return res
from operator import itemgetter
L = [{'key': 'foo', 'v': 42}, {'key': 'bar', 'v': 43}, {'key': 'foo', 'v': 44}]
print unique(L, key=itemgetter('key'))
#[{'key': 'foo', 'v': 42}, {'key': 'bar', 'v': 43}]
I'm not sure this sort of thing admits a one-liner, but it seems to me that the set class is the key to what you want.
M = []
uniques = set(d[x] for d in L)
for d in L:
if d[x] in uniques:
uniques.remove(d[x])
M.append(d)
Note: phihag's answer seems more Pythonic, but this might be a bit more self-documenting
Using dictionary comprehension:
def unique(itrable,key):
return {key(x):x for x in itrable}.values()
>>> unique('abcdbbcdab', lambda x: x)
['a', 'c', 'b', 'd']
>>> unique([10, -20, 20, 30], lambda x: abs(x))
[10, 20, 30]

Categories