This might be very simple, but I'm not sure what to do here.
In Python, I want to go through a list like:
full_list = ["A/A/A", "A/A/B", "B/B/B", "A/C/B"]
and get a dictionary with a kind of tree structure based on these labels, like this:
dictionary = {"A:{"A":["A", "B"], "C":["B"]},"B":{"B":["B]}}
but I'm not sure how to do it. I realize that I need some nested for loops. I know about the split() function in Python.
You can use recursion with collections.defaultdict:
from collections import defaultdict
def to_tree(data):
d = defaultdict(list)
for a, *b in data:
d[a].append(b)
return {a:[i for [i] in b] if all(len(i) == 1 for i in b) else to_tree(b)
for a, b in d.items()}
full_list = ["A/A/A", "A/A/B", "B/B/B", "A/C/B"]
result = to_tree([i.split('/') for i in full_list])
Output:
{'A': {'A': ['A', 'B'], 'C': ['B']}, 'B': {'B': ['B']}}
Making the leaf nodes list entries instead of empty dictionaries makes this trickier IMO -- I'd rethink that aspect of it.
>>> full_list = ["A/A/A", "A/A/B", "B/B/B", "A/C/B"]
>>> from collections import defaultdict
>>> dictionary = defaultdict(lambda: defaultdict(list))
>>> for entry in full_list:
... node = dictionary
... for path in entry.split("/"):
... if isinstance(node, dict):
... node = node[path]
... else:
... node.append(path)
...
>>> dictionary
defaultdict(<function <lambda> at 0x000001C8098171F0>, {'A': defaultdict(<class 'list'>, {'A': ['A', 'B'], 'C': ['B']}), 'B': defaultdict(<class 'list'>, {'B': ['B']})})
Related
The problem that I have is hard to explain, easy to understand:
I have a list of tuples:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
from this list I want to createa dictionary where the keys are the first elements of the tuples ('a' and 'b') and the values associated are in a list:
expected output:
{'a':['111','333'],'b':['222','444']}
How can I solve this problem?
d={}
for x in range (len(L)):
d[L[x][0]]=[L[x][1]]
return d
but as you can easy understand, the output won't be complete since the list will show just the last value associated to that key in L
You can use setdefault() to set the key in the dict the first time. Then append your value:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
d = {}
for key, value in L:
d.setdefault(key, []).append(value)
print(d)
# {'a': ['111', '333'], 'b': ['222', '444']}
You have to append L[x][1] to an existing list, not replace whatever was there with a new singleton list.
d={}
for x in range (len(L)):
if L[x][0] not in d:
d[L[x][0]] = []
d[L[x][0]].append(L[x][1])
return d
A defaultdict makes this easier:
from collections import defaultdict
d = defaultdict(list)
for x in range(len(L)):
d[L[x][0]].append(L[x][1])
return d
A more idiomatic style of writing this would be to iterate directly over the list and unpack the key and value immediately:
d = defaultdict(list)
for key, value in L:
d[key].append(value)
You can try this:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = {}
for item in L:
if item[0] not in my_dict:
my_dict[item[0]] = []
my_dict[item[0]].append(item[1])
print(my_dict)
Output:
python your_script.py
{'a': ['111', '333'], 'b': ['222', '444']}
As pointed by #chepner, you can use defaultdict to.
Basically, with defaultdict you'll not need to check if there is no key yet in your dict.
So it would be:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = defaultdict(list)
for item in L:
my_dict[item[0]].append(item[1])
print(my_dict)
And the output:
defaultdict(<class 'list'>, {'a': ['111', '333'], 'b': ['222', '444']})
And if you want to get a dict from the defaultdict, you can simply create a new dict from it:
print(dict(my_dict))
And the output will be:
{'a': ['111', '333'], 'b': ['222', '444']}
I am working on a compression algorithm for a specific data structure and part of it requires changing a string into a dictionary as follows:
"abc" => {'a':{'b':{'c':{}}}
Which is a group of nested dictionaries based on the letters of the word.
How can I do this in a recursive manner in python?
You can use recursion with list slicing:
def to_dict(d):
return {} if not d else {d[0]:to_dict(d[1:])}
print(to_dict('abc'))
Output:
{'a': {'b': {'c': {}}}}
This is one way:
s = 'abc'
d = {}
current = d
for c in s:
current = current.setdefault(c, {})
print(d)
# {'a': {'b': {'c': {}}}}
Here's a solution using reduce:
from functools import reduce
seq = 'abc'
result = reduce(lambda value, key: { key : value }, reversed(seq), {})
print(result)
Output
{'a': {'b': {'c': {}}}}
This question already has answers here:
Grouping Python dictionary keys as a list and create a new dictionary with this list as a value
(2 answers)
Closed 4 years ago.
I have a list of dictionaries. How can i group that list by valaues.
list = [{a:1},{b:2},{c:1},{d:3},{e:2}]
Now my result should be like below
1:a,c
2:b,e
3:d
I tried using groupby from itertools. But i couldn't get the required result. I am using python 2.7.
Could you help me achieve this?
If you want to use groupby, the list has to be sorted by the same key you want to group by.
>>> lst = [{'a':1}, {'b':2}, {'c':1}, {'d':3}, {'e':2}]
>>> keyfunc = lambda d: next(iter(d.values()))
>>> sorted(lst, key=keyfunc)
[{'a': 1}, {'c': 1}, {'b': 2}, {'e': 2}, {'d': 3}]
>>> {k: [x for d in g for x in d]
... for k, g in itertools.groupby(sorted(lst, key=keyfunc), key=keyfunc)}
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Here's a possible solution without using any library.
def get_dict(list):
res = {}
for elem in list:
k, v = elem.keys(), elem.values()
if v[0] in res:
res[v[0]].append(k[0])
else:
res[v[0]] = [k[0]]
return res
With a list like yours, this would output a dictionary with the following format:
{ 1:[a,c], 2:[b, e], 3:[c] }
This is considering you're always going to have the same format as input. If not, you could just adjust what is read and saved.
This might help.
list = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
d = {}
for i in list:
key, value = i.items()[0]
if value not in d:
d[value] = [key]
else:
d[value].append(key)
print(d)
Output:
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Tested in python2.7
Here is a way to do what you are looking for:
list_ = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
values = set(value for dic in list_ for value in dic.values())
for value in values:
keys = [list(dic.keys())[0] for dic in list_ if value in dic.values()]
print("{}: {}".format(value, keys))
Output:
1: ['a', 'c']
2: ['b', 'e']
3: ['d']
Here's a solution that uses defaultdict.
from __future__ import print_function
from collections import defaultdict
lst = [{'a': 1}, {'b': 2}, {'c': 1}, {'d': 3}, {'e': 2}]
d = defaultdict(list)
for l in lst:
val, key = l.items()[0]
d[key].append(val)
print(d)
Output:
defaultdict(<type 'list'>, {1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']})
I know we can search for a key in Python like this:
if key in myDict:
#Do something here
I know we can extend this and search for the key in multiple dictionaries using elif statement
if key in myDict_1:
#Do something here
elif key in myDict_2:
#Do something here
or by doing
if key in (myDict_1.keys() + myDict_2.keys()):
#Do something here
But is there a more succinct way to search for key in Python in two different dicts without using if-else or adding the list of keys explicitly ?
The answer to your question as written is:
if any(key in d for d in dicts):
# do something
If you need to know which dictionary or dictionaries contain the key, you can use itertools.compress():
>>> d1 = dict(zip("kapow", "squee"))
>>> d2 = dict(zip("bar", "foo"))
>>> d3 = dict(zip("xyz", "abc"))
>>> dicts = d1, d2, d3
>>> from pprint import pprint
>>> pprint(dicts)
({'a': 'q', 'k': 's', 'o': 'e', 'p': 'u', 'w': 'e'},
{'a': 'o', 'b': 'f', 'r': 'o'},
{'x': 'a', 'y': 'b', 'z': 'c'})
>>> from itertools import compress
>>> for d_with_key in compress(dicts, ("a" in d for d in dicts)):
... print(d_with_key)
...
{'a': 'q', 'p': 'u', 'k': 's', 'w': 'e', 'o': 'e'}
{'a': 'o', 'r': 'o', 'b': 'f'}
The correct way would be as Zero wrote:
if any(key in d for d in dicts): # do something
Fixing after reading comments below, thanks to #jwodder:
But you can also create a tuple of the keys of both (or more) dictionaries using the itertools.chain function.
>>> a = {1:2}
>>> b = {3:4}
>>> c = {5:6, 7:8}
>>> print(tuple(itertools.chain(a, b, c)))
(1, 3, 5, 7)
so you also can :
if x in tuple(itertools.chain(a, b, c)):
# Do something
A little list comprehension is also possible here; if you're simply trying to ascertain if a key is in a container of dicts, any() does exactly that; if you want to get the dict (or dicts) back and work with them, perhaps something like this would suffice:
>>> def get_dicts_with_key(some_key, *dicts):
... return [d for d in dicts if some_key in d]
>>> dict1 = {"hey":123}
>>> dict2 = {"wait":456}
>>> get_dicts_with_key('hey', dict1, dict2)
[{'hey': 123}]
>>> get_dicts_with_key('wait', dict1, dict2)
[{'wait': 456}]
>>> get_dicts_with_key('complaint', dict1, dict2)
[]
If the keys were present in either dict, both would be returned, as such:
>>> dict1['complaint'] = 777
>>> dict2['complaint'] = 888
>>> get_dicts_with_key('complaint', dict1, dict2)
[{'complaint': 777, 'hey': 123}, {'complaint': 888, 'wait': 456}]
>>>
Why don't you put your dicts in an iterable like a list and simple loop over then? You can express it as a function like so.
def has_key(key, my_dicts):
for my_dict in my_dicts:
if key in my_dict:
return True
return False
It would be used like so.
>>> dict1 = {'a':1, 'b': 2}
>>> dict2 = {'b':10, 'c': 11}
>>> has_key('b', [dict1, dict2])
True
I need a little bit of homework help. I have to write a function that combines several dictionaries into new dictionary. If a key appears more than once; the values corresponding to that key in the new dictionary should be a unique list. As an example this is what I have so far:
f = {'a': 'apple', 'c': 'cat', 'b': 'bat', 'd': 'dog'}
g = {'c': 'car', 'b': 'bat', 'e': 'elephant'}
h = {'b': 'boy', 'd': 'deer'}
r = {'a': 'adam'}
def merge(*d):
newdicts={}
for dict in d:
for k in dict.items():
if k[0] in newdicts:
newdicts[k[0]].append(k[1])
else:
newdicts[k[0]]=[k[1]]
return newdicts
combined = merge(f, g, h, r)
print(combined)
The output looks like:
{'a': ['apple', 'adam'], 'c': ['cat', 'car'], 'b': ['bat', 'bat', 'boy'], 'e': ['elephant'], 'd': ['dog', 'deer']}
Under the 'b' key, 'bat' appears twice. How do I remove the duplicates?
I've looked under filter, lambda but I couldn't figure out how to use with (maybe b/c it's a list in a dictionary?)
Any help would be appreciated. And thank you in advance for all your help!
Just test for the element inside the list before adding it: -
for k in dict.items():
if k[0] in newdicts:
if k[1] not in newdicts[k[0]]: # Do this test before adding.
newdicts[k[0]].append(k[1])
else:
newdicts[k[0]]=[k[1]]
And since you want just unique elements in the value list, then you can just use a Set as value instead. Also, you can use a defaultdict here, so that you don't have to test for key existence before adding.
Also, don't use built-in for your as your variable names. Instead of dict some other variable.
So, you can modify your merge method as:
from collections import defaultdict
def merge(*d):
newdicts = defaultdict(set) # Define a defaultdict
for each_dict in d:
# dict.items() returns a list of (k, v) tuple.
# So, you can directly unpack the tuple in two loop variables.
for k, v in each_dict.items():
newdicts[k].add(v)
# And if you want the exact representation that you have shown
# You can build a normal dict out of your newly built dict.
unique = {key: list(value) for key, value in newdicts.items()}
return unique
>>> import collections
>>> import itertools
>>> uniques = collections.defaultdict(set)
>>> for k, v in itertools.chain(f.items(), g.items(), h.items(), r.items()):
... uniques[k].add(v)
...
>>> uniques
defaultdict(<type 'set'>, {'a': set(['apple', 'adam']), 'c': set(['car', 'cat']), 'b': set(['boy', 'bat']), 'e': set(['elephant']), 'd': set(['deer', 'dog'])})
Note the results are in a set, not a list -- far more computationally efficient this way. If you would like the final form to be lists then you can do the following:
>>> {x: list(y) for x, y in uniques.items()}
{'a': ['apple', 'adam'], 'c': ['car', 'cat'], 'b': ['boy', 'bat'], 'e': ['elephant'], 'd': ['deer', 'dog']}
In your for loop add this:
for dict in d:
for k in dict.items():
if k[0] in newdicts:
# This line below
if k[1] not in newdicts[k[0]]:
newdicts[k[0]].append(k[1])
else:
newdicts[k[0]]=[k[1]]
This makes sure duplicates aren't added
Use set when you want unique elements:
def merge_dicts(*d):
result={}
for dict in d:
for key, value in dict.items():
result.setdefault(key, set()).add(value)
return result
Try to avoid using indices; unpack tuples instead.