Related
I have two lists of rows, each with two rows, like this:
list1 = [{'a': 'foo', 'b': 'bar', 'c': 'baz'}, {'d': 'qux', 'e': 'quux', 'f': 'quuz'}]
list2 = [{'g': 'corge', 'h': 'grault', 'i': 'garply'}, {'j': 'waldo', 'k': 'fred', 'l': 'plugh'}]
I would like to join the two lists so that row 1 from list 1 is joined with row 1 from list 2 and row 2 from list 1 is joined with row 2 from list 2, like this:
final_list = [{'a': foo, 'b': bar 'c': baz, 'g': corge, 'h': grault, 'i': garply}, {'d': qux, 'e': quux, 'f': quuz, 'j': waldo, 'k': fred, 'l': plugh}]
I have tried:
final_list = [[i, j] for i,j in zip(list1, list2)]
But it doesn't quite join them correctly. Instead, it produces:
[{'a': foo, 'b': bar 'c': baz}, {'g': corge, 'h': grault, 'i': garply}], [{'d': qux, 'e': quux, 'f': quuz}, {'j': waldo, 'k': fred, 'l': plugh}]
I would like to join these lists of rows so that I can then loop through them with Jinja on an HTML page. How can I resolve this issue?
Your list comprehension should be creating a new dictionary, rather than a list of dictionaries, for each element in the result from zip():
list1 = [
{'a': 'foo', 'b': 'bar', 'c': 'baz'},
{'d': 'qux', 'e': 'quux', 'f': 'quuz'}
]
list2 = [
{'g': 'corge', 'h': 'grault', 'i': 'garply'},
{'j': 'waldo', 'k': 'fred', 'l': 'plugh'}
]
# Can also use "x | y" in place of "{**x, **y}" if on Python 3.9+
result = [{**x, **y} for x, y in zip(list1, list2)]
print(result)
This outputs:
[
{'a': 'foo', 'b': 'bar', 'c': 'baz', 'g': 'corge', 'h': 'grault', 'i': 'garply'},
{'d': 'qux', 'e': 'quux', 'f': 'quuz', 'j': 'waldo', 'k': 'fred', 'l': 'plugh'}
]
You can actually use the update function which can be used to merge two python dictionaries and is very simple and easy to use.
a = [
{"a": "foo", "b": "bar", "c": "baz"},
{"d": "qux", "e": "quux", "f": "quuz"},
]
b = [
{"g": "corge", "h": "grault", "i": "garply"},
{"j": "waldo", "k": "fred", "l": "plugh"},
]
for i in range(len(a)):
a[i].update(b[i])
print(a)
The output is as
[{'a': 'foo', 'b': 'bar', 'c': 'baz', 'g': 'corge', 'h': 'grault', 'i': 'garply'}, {'d': 'qux', 'e': 'quux', 'f': 'quuz', 'j': 'waldo', 'k': 'fred', 'l': 'plugh'}]
Your items are dictionary objects…
You can create a new dict out of the two… the keys of the last dict will overwrite the values if any are the same. The below is using the dict unpacking operator **.
final_lst = [{**d1, **d2} for d1, d2 in zip(lst1, lst2)]
There are other ways as well. Removed first example as it wasn’t correct.
I have a dictionary like this
{'C':
{
'G':
{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]
}
}
}
and I'm trying to convert to list each value that is a dictionary in order to get a new dictionary like this
{'C':
[{
'G':
[{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]
}]
}]
}
To see it easely would be pass from dict1 to dict2
My attempt so far is like this. Thanks in advance.
>>> for k, v in d1.items():
... if isinstance(v, dict):
... d1[k,v] = d1[k,[v]]
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: unhashable type: 'list'
You can use recursion:
def to_list(d):
if not isinstance(d, (dict, list)):
return d
if isinstance(d, list):
return list(map(to_list, d))
return {a:to_list(b) if not isinstance(b, dict) else [to_list(b)] for a, b in d.items()}
vals = {'C': {'G': {'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]}}}
r = to_list(vals)
Output:
{'C': [{'G': [{'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]}]}]}
If you want your key to be k then you don't want d1[k,v], rather you should set d1[k] = [v]
Note that you have not provided a way to go deeper into the dictionary, this will only convert top-level values that are dicts to lists containing the dict. You'll need a way to recurse into those dicts if you wish to convert any dicts that they contain as values.
You can try recursion:
dct = {
"C": {
"G": {
"Z": "4",
"L": "1",
"P": [{"K": "3", "B": "1"}, {"K": "7", "B": "9"}],
}
}
}
def convert(d):
if isinstance(d, dict):
out = {}
for k, v in d.items():
out[k] = [convert(v)] if isinstance(v, dict) else convert(v)
return out
elif isinstance(d, list):
return [convert(v) for v in d]
return d
print(convert(dct))
Prints:
{
"C": [
{
"G": [
{
"Z": "4",
"L": "1",
"P": [{"K": "3", "B": "1"}, {"K": "7", "B": "9"}],
}
]
}
]
}
Recursive approach
d = {'C':
{
'G':
{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]
}
}
}
def d2l(d):
for k, v in d.items():
if isinstance(v, dict):
d2l(v)
d[k] = [v]
return d
new_dict = d2l(d)
print(new_dict)
Output
{'C': [{'G': [{'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]}]}]}
I would use recursion, this seemed to work for me:
main = {
'C': {
'G': {
'Z': '4',
'L': '1',
'P': [{'K': '3', 'B': '1'},
{'K': '7', 'B': '9'}]
}
}
}
def convert_dictionary(dictionary: dict):
for key, value in dictionary.items():
if isinstance(value, dict):
convert_dictionary(value)
dictionary[key] = [value]
convert_dictionary(main)
print(main)
Tell me if it helped!
Yet another recursion solution (added a third level)
def toList(d, d2):
for k, v in d.items():
if isinstance(v, dict):
d2[k] = [v]
toList(v, d2[k][0])
d1 = {'C':
{
'G':
{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}],
"thirdLvl": {'K': '7', 'B': '9'}
}
}
}
d2 = {}
toList(d1,d2)
print(d2)
Result:
{'C':
[{'G':
[{'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}],
'thirdLvl': [{'K': '7', 'B': '9'}]
}
]
}
]
}
I have two lists
a = ['b','c','a','d','v']
g = [{'c':'1'},{'c':'2'},{'c':'3'},{'d':'1'},{'d':'2'}]
I want to match the key in the dictionary in the list g to the elements in list a, if they are matched, the elements in list g will be inserted into list a.
The desired outcome is:
['b','c',{'c':'1'},{'c':'2'},{'c':'3'},'a','d',{'d':'1'},{'d':'2'},'v']
Try:
a = ["b", "c", "a", "d", "v"]
g = [{"c": "1"}, {"c": "2"}, {"c": "3"}, {"d": "1"}, {"d": "2"}]
tmp = {}
for d in g:
for k in d:
tmp.setdefault(k, []).append(d)
out = []
for v in a:
out.append(v)
out.extend(tmp.get(v, []))
print(out)
Prints:
['b', 'c', {'c': '1'}, {'c': '2'}, {'c': '3'}, 'a', 'd', {'d': '1'}, {'d': '2'}, 'v']
Try using sorted:
print(sorted(a + g, key=lambda x: list(x)[0]))
Output:
['a', 'b', 'c', {'c': '1'}, {'c': '2'}, {'c': '3'}, 'd', {'d': '1'}, {'d': '2'}, 'e']
a = ['a','b','c','d','e']
g = [{'c':'1'},{'c':'2'},{'c':'3'},{'d':'1'},{'d':'2'},{'z':'1'}]
for dic in g:
for key in dic:
if key in a:
a.append(dic)
print(a)
#output ['a', 'b', 'c', 'd', 'e', {'c': '1'}, {'c': '2'}, {'c': '3'}, {'d': '1'}, {'d': '2'}]
After this, you can do sorting using lambda if required.
I have a list of dictionaries, each containing two identical keys with possibly different values:
list_of_dicts = [
{'a': '1', 'b': '1'},
{'a': '4', 'b': '4'},
{'a': '1', 'b': '1'},
{'a': '3', 'b': '0'},
{'a': '1', 'b': '2'},
{'a': '4', 'b': '99'}
]
I want to rearrange this structure so that the values of one of the keys is a key, and the value is a dictionary of the other values (more keys will be added to these dictionaries later).
I also want to retain the different values for those keys (without duplicates). So the result should look like:
{'1': {'b': {'1', '2'}}, '4': {'b': {'4', '99'}}, '3': {'b': {'0'}}}
The purpose of this is to
remove duplicate values of 'a'
be able to call a dict based on the keys 1,4,3 in this example
retain the information held in the other key-value
This is the code I wrote to do this:
newdict = \
{d['a']: { #for each unique a value, build a dict with key b containing a set of all b values
'b':{d['b']} | {another_d['b'] for another_d in list_of_dicts if another_d['a'] == d['a']}
} \
for d in list_of_dicts}
but I'm wondering if there's a more idiomatic or cleaner way to write this? I tried using d.get() but I don't think it can be used.
Try:
list_of_dicts = [
{"a": "1", "b": "1"},
{"a": "4", "b": "4"},
{"a": "1", "b": "1"},
{"a": "3", "b": "0"},
{"a": "1", "b": "2"},
{"a": "4", "b": "99"},
]
out = {}
for d in list_of_dicts:
for k in d.keys() ^ "a":
out.setdefault(d["a"], {}).setdefault(k, set()).add(d[k])
print(out)
Prints:
{'1': {'b': {'1', '2'}}, '4': {'b': {'99', '4'}}, '3': {'b': {'0'}}}
I am trying to merge the list of dictionaries inside a list based on a value of key "host". The sample input for the same looks like:
first = [{'host': '1', 'a': 'a', 'b': 'b'}, {'host': '2', 'a': 'c', 'd': 'd'}, {'host': '3', 'a': 'd', 'd': 'd'}]
second = [{'host': '1', 'a': 'w', 'b': 'e'}, {'host': '2', 'a': 'q', 'd': 's'}, {'host': '3', 'a': 'q', 'd': 'c'}]
third= [{'host': '1', 'a': 'r', 'b': 't'}, {'host': '2', 'a': 'f', 'd': 'b'}, {'host': '3', 'a': 'k', 'd': 'p'}]
I am trying to get output like this
final_list = {
"1": [
{ "host": "1", "a": "a", "b": "b" },
{ "host": "1", "a": "w", "b": "e" },
{ "host": "1", "a": "r", "b": "t" }
],
"2": [
{ "host": "2", "a": "c", "d": "d" },
{ "host": "2", "a": "q", "d": "s" },
{ "host": "2", "a": "f", "d": "b" }
],
"3": [
{ "host": "3", "a": "d", "d": "d" },
{ "host": "3", "a": "q", "d": "c" },
{ "host": "3", "a": "k", "d": "p" }
]
}
You want to zip them pairwise and then use enumerate to annotate the pairs starting at 1.
final_list = {str(num): [a, b, c] for num, (a, b, c) in
enumerate(zip(first, second, third), start = 1)}
>>> final_list
{'1': [{'a': 'a', 'b': 'b', 'host': '1'},
{'a': 'w', 'b': 'e', 'host': '1'},
{'a': 'r', 'b': 't', 'host': '1'}],
'2': [{'a': 'c', 'd': 'd', 'host': '2'},
{'a': 'q', 'd': 's', 'host': '2'},
{'a': 'f', 'd': 'b', 'host': '2'}],
'3': [{'a': 'd', 'd': 'd', 'host': '3'},
{'a': 'q', 'd': 'c', 'host': '3'},
{'a': 'k', 'd': 'p', 'host': '3'}]}
I gathered your List for simpler use and you can do that:
first = [{'host': '1', 'a': 'a', 'b': 'b'}, {'host': '2', 'a': 'c', 'd': 'd'}, {'host': '3', 'a': 'd', 'd': 'd'}]
second = [{'host': '1', 'a': 'w', 'b': 'e'}, {'host': '2', 'a': 'q', 'd': 's'}, {'host': '3', 'a': 'q', 'd': 'c'}]
third= [{'host': '1', 'a': 'r', 'b': 't'}, {'host': '2', 'a': 'f', 'd': 'b'}, {'host': '3', 'a': 'k', 'd': 'p'}]
final_dict = {}
allList = [first, second, third]
for aList in allList:
for aDict in aList:
if aDict["host"] not in final_dict.keys():
final_dict[aDict["host"]] = [aDict]
else:
final_dict[aDict["host"]].append([aDict])
print(final_dict)