Reputation: 5412
Following is the keys which will be used to create a dictionary.
keys = ['a', 'b','c']
adding to the challenge is that list of lists of values with varying level of nesting within the items, these need to be flattened but only if it has only one item. For example, [3,3,5]
shouldn't be flattened because it represent a group.
values = [
[[1],[1],[1]],
[[1],[0],1],
[2,0,[3,3,5]],
[1,[[1]],0]
]
I tried print dict(zip(key_list, cols))
but this doesn't seem to quite generate the expected output:
[{'a':1, 'b':1, 'c':1} , {'a':1, 'b':0, 'c':1}, {'a':2, 'b':0, 'c':[3,3,5]}]
Upvotes: 0
Views: 134
Reputation: 5275
You can write a recursive function which can flatten your list based on level of nested list you have.
Like in your case max level of nested list is 2 for [[1]]
def get_values(values,count):
for i in range(count):
count = count - 1
values = [[each[0] if isinstance(each, list) and len(each) ==1 else each for each in val] for val in values]
return get_values(values,count)
else:
return values
keys = ['a', 'b','c']
values = [
[[1],[1],[1]],
[[1],[0],1],
[2,0,[3,3,5]],
[1,[[1]],0]
]
count = max([str(each).count('[') for row in values for each in row if isinstance(each, list)])
# count = 2
print [dict(zip(keys, each)) for each in get_values(values, count)]
Results:
[{'a': 1, 'c': 1, 'b': 1}, {'a': 1, 'c': 1, 'b': 0},
{'a': 2, 'c': [3, 3, 5], 'b': 0}, {'a': 1, 'c': 0, 'b': 1}]
If the level of max nesting is 3 you just have to pass 3 as a parameter to the recursive function.
For example here values have max nesting of level 3 for element [[[1]]]
so we just have to pass 3 as count parameter value for get_values
function :
keys = ['a', 'b','c']
values = [
[[1],[1],[1]],
[[1],[0],1],
[2,0,[3,3,5]],
[1,[[[1]]],0]
]
count = max([str(each).count('[') for row in values for each in row if isinstance(each, list)])
# count = 3
print [dict(zip(keys, each)) for each in get_values(values, count)]
Results:
[{'a': 1, 'c': 1, 'b': 1}, {'a': 1, 'c': 1, 'b': 0},
{'a': 2, 'c': [3, 3, 5], 'b': 0}, {'a': 1, 'c': 0, 'b': 1}]
Upvotes: 0
Reputation: 52071
Given your input and expected output, you can overcome the single nested challenge by using loops. The program can be written as
values = [
[[1],[1],[1]],
[[1],[0],1],
[2,0,[3,3,5]],
[1,[[1]],0]
]
keys = ['a','b','c']
l = []
for i in values:
d = dict()
for j in range(3):
ele = i[j]
while isinstance(ele,list) and len(ele) == 1:
ele = ele[0]
else:
d[keys[j]] = ele
l.append(d)
print (l)
With the output
[{'a': 1, 'b': 1, 'c': 1}, {'a': 1, 'b': 0, 'c': 1}, {'a': 2, 'b': 0, 'c': [3, 3, 5]}, {'a': 1, 'b': 1, 'c': 0}]
as expected. (but as dictionaries are hashed the order would have been different)
NOTE - I have used SHORT CIRCUIT EVALUATION to prevent use of multiple condition statements
Upvotes: 2
Reputation: 31339
Because of deep-nesting you need to recursively or iteratively flatten single element lists. I used get_flat
to do it according to your specification.
#!/usr/bin/env python
# flatten single element lists recursively.
# using a while loop is probably better
def get_flat(elem):
if isinstance(elem, list):
if len(elem) > 1:
return elem
else:
return get_flat(elem[0])
return elem
values = [
[[1],[1],[1]],
[[1],[0],1],
[2,0,[3,3,5]],
[1,[[1]],0]
]
keys = ['a','b', 'c']
# zip keys and values for each flat column (uses get_flat to flatten)
# and convert to dict
print map(dict, map(lambda col: zip(keys, map(get_flat, col)), values))
Output:
[{'a': 1, 'c': 1, 'b': 1}, {'a': 1, 'c': 1, 'b': 0}, {'a': 2, 'c': [3, 3, 5], 'b': 0}, {'a': 1, 'c': 0, 'b': 1}]
Upvotes: 1
Reputation: 107287
At the first you need to flat your values , you can do it with following recursion function :
>>> def flat(l):
... if not any(isinstance(i,list) and len(i)==1 for v in l for i in v):
... return l
... else :
... return flat([[i[0] if isinstance(i,list) and len(i)==1 else i for i in v] for v in l])
...
>>> flat(values)
[[1, 1, 1], [1, 0, 1], [2, 0, [3, 3, 5]], [1, 1, 0]]
then use the following list comprehension :
>>> [dict(zip(keys,l)) for l in flat(values)]
[{'a': 1, 'c': 1, 'b': 1}, {'a': 1, 'c': 1, 'b': 0}, {'a': 2, 'c': [3, 3, 5], 'b': 0}, {'a': 1, 'c': 0, 'b': 1}]
but this gave you a dictionary list with 4 item , and you want 3 , mean that you want one dict for [1, 0, 1]
and [1, 1, 0]
, thus you need to remove one of them you can do it with sorted them and an list comprehension :
>>> p=[sorted(i) for i in flat(values)]
>>> [j for i,j in enumerate(p) if p[i+1:].count(j)<1]
[[1, 1, 1], [0, 2, [3, 3, 5]], [0, 1, 1]]
>>> [dict(zip(keys,l)) for l in last_l]
[{'a': 1, 'c': 1, 'b': 1}, {'a': 0, 'c': [3, 3, 5], 'b': 2}, {'a': 0, 'c': 1, 'b': 1}]
Upvotes: 0
Reputation: 23827
I'm assuming your last sentence means [{'a':1, 'b':1, 'c':1} , {'a':1, 'b':0, 'c':1}, {'a':2, 'b':0, 'c':[3,3,5]}] is your expected output.
Then
keys = ['a', 'b', 'c']
values = [
[[1],[1],[1]],
[[1],[0],1],
[2,0,[3,3,5]],
[1,[[1]],0]
]
print [dict(zip(keys, entry)) for entry in values]
is your desired result.
[{'a': [1], 'b': [1], 'c': [1]}, {'a': [1], 'b': [0], 'c': 1}, {'a': 2, 'b': 0, 'c': [3, 3, 5]}, {'a': 1, 'b': [[1]], 'c': 0}]
Your problem is that zip(keys,values) treats each list making up values as the value that the key will point to. So you got
{'a': [[1], [1], [1]], 'c': [2, 0, [3, 3, 5]], 'b': [[1], [0], 1]}
Upvotes: -1