python flatten/unwrap list of dictionaries in list - python

I have list of dictionaries in list like below
A = [[{'a': '1', 'b': '2'}],[{...}],[{...}],[],[],[{'x': '25', 'z':'26'}]]
7 lists of dictionaries inside a list "A" (data from 7days)
python using for loop in def function
some lists of dictionaries inside A has data, some doesn't
I want to flatten/unwrap like this into a different list B
B = [{'a': '1', 'b': '2', ..., 'x': '25', 'z':'26'}]
as a list of dictionaries.
I have tried(with corresponding imports):
B = (list(itertools.chain(*A)))
B = [item for sublist in A for item in sublist]
B = [dict(chain(*map(dict.items, d.values()))) for d in A]
Above 3 flattening/unwrapping methods give me an empty list [] as a result.
I want to do this because just one list will fit to my ajax append format in html
that will be applied for data sets for month, quarter, half-year, and year as well.(I also need to flatten 365 lists of dictionaries in a list with for loop is used to create this list)
Am I using above method wrong?
Does flattening/unwrapping has to follow the each unorganized list of lists' structure?
Is it better not to create the unorganized list like list A by changing for loop from python using for loop in def function ?
EDIT: I separated unflatten list(A) and flatten list(B) in the question.

You can use itertools.chain() and dict comprehension:
A = [[{1:1, 2:2}], [], [{3:3}], [{8:8}], [], [], [{9:9}]]
b = itertools.chain(*A)
{k:v for x in b for k,v in x.items()}
Expected result:
{1: 1, 2: 2, 3: 3, 8: 8, 9: 9}
More about itertools: https://www.geeksforgeeks.org/python-itertools/
More about dict comprehension: https://www.programiz.com/python-programming/dictionary-comprehension

Related

Dictionary comprehension returning ValueError: not enough values to unpack (expected 2, got 1)

I have a list of dictionaries with hundreds of entries like this
lst = [{'A':'0.1'},{'B':'0.1'},{'C':'0.01'},{'D':'0.0001'},{'E':'0.01'}]
I am trying to sort the key:value pairs into separate lists using dictionary comprehension
lst1 = []
lst2 = []
lst3 = []
lst1.append({key:value for (key,value) in lst if value == '0.1'})
lst2.append({key:value for (key,value) in lst if value == '0.01'})
lst3.append({key:value for (key,value) in lst if value == '0.0001'})
I am then using an if statement to check what list a certain key is in.
variable = 'A'
if variable in lst1:
print('A is in lst one')
When i run the code I get ValueError: not enough values to unpack (expected 2, got 1)
First, don't use list as a name. It's the name of a built-in class and you don't want to overwrite it.
What you're trying to do is something like this:
lst = [{'A':'0.1'},{'B':'0.1'},{'C':'0.01'},{'D':'0.0001'},{'E':'0.01'}]
list1 = [dic for dic in lst if list(dic.values())[0]== '0.1']
list2 = [dic for dic in lst if list(dic.values())[0]== '0.01']
list3 = [dic for dic in lst if list(dic.values())[0]== '0.0001']
print(list1)
print(list2)
print(list3)
outputs:
[{'A': '0.1'}, {'B': '0.1'}]
[{'C': '0.01'}, {'E': '0.01'}]
[{'D': '0.0001'}]
Note that list(dic.values()) wouldn't have made any sense (it would produce an error) had I overwritten list.
And later:
variable = 'A'
for item in list1:
if variable in item.keys():
print('A is in list one')
which can be encapsulated in a function:
def find_key(variable):
for item in list1:
if variable in item.keys():
print(f'{variable} is in list one')
find_key('A')
A is in list one
Now, do you really need to use dictionaries with one key, value pair each one? Do you need to store those in a list? I'm not sure what you're trying to do, but seems like a XY problem. Try to think whether there is a simpler, more elegant way of doing it.
The same for the second part: are you going to make a separate function for each list?
This works perfectly!
lst = [{'A':'0.1'},{'B':'0.1'},{'C':'0.01'},{'D':'0.0001'},{'E':'0.01'}]
print(dict([list(d.items())[0] for d in lst if list(d.items())[0][1] == '0.1']))
print(dict([list(d.items())[0] for d in lst if list(d.items())[0][1] == '0.01']))
print(dict([list(d.items())[0] for d in lst if list(d.items())[0][1] == '0.0001']))
output
{'A': '0.1', 'B': '0.1'}
{'C': '0.01', 'E': '0.01'}
{'D': '0.0001'}
thanks to Psidom

How to merge values of two arrays into one? [duplicate]

This question already has answers here:
How to merge lists into a list of tuples?
(10 answers)
Closed 1 year ago.
How to merge two arrays as value-pairs in python?
Example as follows:
A = [0,2,2,3]
B = [1,1,4,4]
Output:
[[0,1],[2,1],[2,4],[3,4]]
You can simply use "zip"
l1 = [0,2,2,3]
l2 = [1,1,4,4]
print(list(map(list ,zip(l1,l2))))
In addition to Greg's answer, if you need key value pairs cast your zip result to dict
l1 = [0,2,2,3]
l2 = [1,1,4,4]
print(dict(zip(l1,l2)))
Output
{0: 1, 2: 4, 3: 4}
Before creating any loop, try to use built-ins.
Also there is a similar question for your need
Zip with list output instead of tuple
You can simultaniously itterate through using zip(), and append a result list with each of the pairs like so:
A = [0,2,2,3]
B = [1,1,4,4]
result = []
for item1, item2 in zip(A,B):
result.append([item1, item2])
Output = [[0,1],[2,1],[2,4],[3,4]]
print(result) # Prints: [[0,1],[2,1],[2,4],[3,4]]
print(Output == result) # Prints: True
This would give you a list of lists like you were looking for in your question as an output.
Things to keep in mind
If the two starting lists are different sizes then zip() throws away values after one of the lists runs out, so with :
A = [0,2,2,3,4,5]
B = [1,1,4,4]
result = []
for item1, item2 in zip(A,B):
result.append([item1, item2])
Output = [[0,1],[2,1],[2,4],[3,4]]
print(result) # Prints: [[0,1],[2,1],[2,4],[3,4]]
print(Output == result) # Prints: True
You notice that the 4 and 5 in list A is thrown out and ignored.
Key-Value Pair
Also this is not a key-value pair, for that you will want to look into dictionaries in python. That would be something like:
output = {0:1, 2:4, 3:4}
This would allow you to do a lookup for a value, based on it's key like so:
output[3] # Would be 4
output[0] # Would be 1
Which doesn't work for this example because there are two 2's used as keys, so one would be overridden.
Since you have mentioned key-value, you probably mean a dictionary.
A = [0, 2, 2, 3]
B = [1, 1, 4, 4]
dct = {} # Empty dictionary
for key, value in zip(A, B):
dct[key] = value
print(dct)
The output will be:
{0: 1, 2: 4, 3: 4}
Note that, by definition, you can't have two identical keys. So in your case, {2: 1} will be overriden by {2: 4}.

Convert 4 one-to-one mapped lists into a list of dicts (python)

I have 4 lists where the elements are one-to-one mapped. There are tens of thousands of elements. I want to create one dict giving the 4 properties for each element, and then I want to put these dicts into a list. (My end goal is to create a pandas DataFrame and save it as an HDF5 file.)
Is there an easy memory-efficient way to do this, perhaps using zip() and dict() instead of a for loop?
As a working example for Python, please consider:
list1 = ['obj1','obj2','obj3']
list2 = ['cat','dog','tree']
list3 = [7,8,9]
list4 = ['red','green','blue']
So the idea is that in the end I want a list of dicts that looks like
[{'obj':'obj1','type':'cat','num':7,'color':'red'},
{'obj':'obj2','type':'dog','num':8,'color':'green'},
{'obj':'obj3','type':'tree','num':9,'color':'blue'}]
Since you tag pandas , By using to_dict
pd.DataFrame({'obj':list1,'type':list2,'num':list3,'color':list4}).to_dict('r')
Out[1204]:
[{'color': 'red', 'num': 7, 'obj': 'obj1', 'type': 'cat'},
{'color': 'green', 'num': 8, 'obj': 'obj2', 'type': 'dog'},
{'color': 'blue', 'num': 9, 'obj': 'obj3', 'type': 'tree'}]
Here's a non-pandas option:
data = zip(list1, list2, list3, list4)
keys = ['obj', 'type', 'num', 'color']
list_of_dicts = [dict(zip(keys, i)) for i in data]
Instead of a list a dict of dicts
import pandas as pd
import numpy as np
list1 = ['obj1','obj2','obj3']
list2 = ['cat','dog','tree']
list3 = [7,8,9]
list4 = ['red','green','blue']
pd.DataFrame(np.array([list1, list2, list3, list4])).to_dict()
Since it is using corresponding element from each list (first dictionary of the output list is with first element from each input list) and assuming all list are of same size, using list comprehension may be one other way:
[{'obj':list1[i], 'type':list2[i],
'num':list3[i], 'color':list4[i]} for i in range(len(list1))]

Python - Filter list of dictionaries based on if key value contains all items in another list

I have a list of dictionaries that looks like this, but with around 500 items:
listOfDicts = [{'ID': 1, 'abc': {'123': 'foo'}}, ... {'ID': 7, 'abc': {'123':'foo','456': 'bar'}}]
sampleFilterList = ['123', '456']
I am trying to filter the listOfDicts for all the results where all the values in the sampleFilterList are in the key 'abc'
The result should be a list:
[{'ID': 7, 'abc': {'123':'foo','456': 'bar'}}, ...]
I tried [i for i in listOfDicts if a for a in sampleFilterList in i['abc']], but I am getting an UnboundLocalError: local variable 'a' referenced before assignment
First, convert your second list to a set for more efficient comparisons:
sampleFilterSet = set(sampleFilterList)
Now, compare the 'abc' keys for each list item to the aforesaid set:
[item for item in listOfDicts if not (sampleFilterSet - item['abc'].keys())]
#[{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
This is the fastest solution. A more Pythonic (but somewhat slower) solution is to use filter():
list(filter(lambda item: not (sampleFilterSet - item['abc'].keys()), listOfDicts))
#[{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
You need to move the in condition test before the for keyword in the list comprehension and also use get will be more safe, which returns a default value instead of throwing an error, if you are not sure if all the dictionaries in the list have the keyword abc:
listOfDicts = [{'ID': 1, 'abc': {'123': 'foo'}}, {'ID': 7, 'abc': {'123':'foo','456': 'bar'}}] ​
sampleFilterList = ['123', '456']
[d for d in listOfDicts if all(s in d.get('abc', {}) for s in sampleFilterList)]
# [{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
Or if use a set as of #DYZ, you can use issubset:
filterSet = set(sampleFilterList)
[d for d in listOfDicts if filterSet.issubset(d.get('abc', {}))]
# [{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
Here is a working version with nested list comprehensions. Your problem is that the a for a in... is a list comprehension, and needs to be used in constructing a new list.
[i for i in listOfDicts if [a for a in sampleFilterList if a in i['abc']] == sampleFilterList]
You could try the following one-liner:
passed_the_filter = [[dictionary_entry for dictionary_entry in list_of_dicts if filter_test in dictionary_entry['abc']] for filter_test in filter]
It is a nested list comprehension that iterates through both the filter and the dictionary list. It checks if the filter is a key in the dictionary entries' "abc" value. Your problem was that you used the wrong list comprehension syntax.
N.B. You may want to note that you might not be sure that an element has a "abc" key!
Thank you for reading this.
for i in zip(listOfDicts):
a = i[0]['abc']
print (a)
or:
for i in zip(listOfDicts):
if 'abc' in i[0]:
a = i
print (a)
This is an elegant way to do it, I hope it will be useful.

Updating a list of python dictionaries with a key, value pair from another list

Let's say I have the following list of python dictionary:
dict1 = [{'domain':'Ratios'},{'domain':'Geometry'}]
and a list like:
list1 = [3, 6]
I'd like to update dict1 or create another list as follows:
dict1 = [{'domain':'Ratios', 'count':3}, {'domain':'Geometry', 'count':6}]
How would I do this?
>>> l1 = [{'domain':'Ratios'},{'domain':'Geometry'}]
>>> l2 = [3, 6]
>>> for d,num in zip(l1,l2):
d['count'] = num
>>> l1
[{'count': 3, 'domain': 'Ratios'}, {'count': 6, 'domain': 'Geometry'}]
Another way of doing it, this time with a list comprehension which does not mutate the original:
>>> [dict(d, count=n) for d, n in zip(l1, l2)]
[{'count': 3, 'domain': 'Ratios'}, {'count': 6, 'domain': 'Geometry'}]
You could do this:
for i, d in enumerate(dict1):
d['count'] = list1[i]
You can do this:
# list index
l_index=0
# iterate over all dictionary objects in dict1 list
for d in dict1:
# add a field "count" to each dictionary object with
# the appropriate value from the list
d["count"]=list1[l_index]
# increase list index by one
l_index+=1
This solution doesn't create a new list. Instead, it updates the existing dict1 list.
Using list comprehension will be the pythonic way to do it.
[data.update({'count': list1[index]}) for index, data in enumerate(dict1)]
The dict1 will be updated with the corresponding value from list1.

Categories

Resources