Assign keys to the tuple items - python

l1 = [1, 2, 3]
l2 = ['foo', 'bar', 'test']
z1 = zip(l1,l2)
list(z1)
[(1, 'foo'), (2, 'bar'), (3, 'test')]
That's a sample of my code. Now I want to map (??) each value of the tuples to either id, or name.
So I can get a result like :
[('id':1, 'name':'foo'), ('id':2, 'name':'bar'), ('id':3, 'name':'test')]
What I did is :
>>> result = []
>>> for i in zip(l1,l2):
... d['id'] = i[0]
... d['name'] = i[1]
... result.append(d)
>>> result
[{'id': 3, 'name': 'test'}, {'id': 3, 'name': 'test'}, {'id': 3, 'name': 'test'}]
but 1st) it doesn't works and 2nd) not pythonic at all as far as I can tell...
I don't understand why the loop above doesn't works. If I do :
>>> for i in zip(l1,l2):
... print(i[0], i[1])
...
1 foo
2 bar
3 test
it iterates every item without problem and the append() I used above with the list shouldn't cause any problems...

You can write that for loop pythonically using a dict comprehension:
[{'id': id, 'name': name} for id,name in zip(l1, l2)]
Depending on how complex this dict actually is, and what you want to do with it, you might want to consider using a simple class instead.

Id d is your dictionary what you are doing is replacing the values of the keys(id & name) of the dictionary d and your are appending it to a list.
To create a list of dictionary you can use a list comprehension like
l1 = [1, 2, 3]
l2 = ['foo', 'bar', 'test']
result = [{'id': i[0], 'name':i[1]} for i in zip(l1,l2)]

Your solution doesn't work because you are "overriding" the dict at each step :
>>> for i in zip(l1,l2):
... d['id']=i[0]
... d['name']=i[1]
... r.append(d)
... print r
...
[{'id': 1, 'name': 'foo'}]
[{'id': 2, 'name': 'bar'}, {'id': 2, 'name': 'bar'}]
[{'id': 3, 'name': 'test'}, {'id': 3, 'name': 'test'}, {'id': 3, 'name': 'test'}]
One way to go is to "reset" your dict at the beginning of each step:
>>> for i in zip(l1,l2):
... d={}
... d['id']=i[0]
... d['name']=i[1]
... r.append(d)
... print r
...
[{'id': 1, 'name': 'foo'}]
[{'id': 1, 'name': 'foo'}, {'id': 2, 'name': 'bar'}]
[{'id': 1, 'name': 'foo'}, {'id': 2, 'name': 'bar'}, {'id': 3, 'name': 'test'}]
But as others pointed out, [{'id': id, 'name': name} for id, name in zip(l1, l2)] is more pythonic.
And I don't know if you could use it, but you could build your dict from your zip:
>>> dict(zip(l1, l2))
{1: 'foo', 2: 'bar', 3: 'test'}

Related

Python: consolidate list of lists

I want to consolidate a list of lists (of dicts), but I have honestly no idea how to get it done.
The list looks like this:
l1 = [
[
{'id': 1, 'category': 5}, {'id': 3, 'category': 7}
],
[
{'id': 1, 'category': 5}, {'id': 4, 'category': 8}, {'id': 6, 'category': 9}
],
[
{'id': 6, 'category': 9}, {'id': 9, 'category': 16}
],
[
{'id': 2, 'category': 4}, {'id': 5, 'category': 17}
]
]
If one of the dicts from l1[0] is also present in l1[1], I want to concatenate the two lists and delete l1[0]. Afterwards I want to check if there are values from l1[1] also present in l1[2].
So my desired output would eventually look like this:
new_list = [
[
{'id': 1, 'category': 5}, {'id': 3, 'category': 7}, {'id': 4, 'category': 8}, {'id': 6, 'category': 9}, {'id': 9, 'category': 16}
],
[
{'id': 2, 'category': 4}, {'id': 5, 'category': 17}
]
]
Any idea how it can be done?
I tried it with 3 different for loops, but it wouldnt work, because I change the length of the list and by doing so I provoke an index-out-of-range error (apart from that it would be an ugly solution anyway):
for list in l1:
for dictionary in list:
for index in range(0, len(l1), 1):
if dictionary in l1[index]:
dictionary in l1[index].append(list)
dictionary.remove(list)
Can I apply some map or list_comprehension here?
Thanks a lot for any help!
IIUC, the following algorithm works.
Initialize result to empty
For each sublist in l1:
if sublist and last item in result overlap
append into last list of result without overlapping items
otherwise
append sublist at end of result
Code
# Helper functions
def append(list1, list2):
' append list1 and list2 (without duplicating elements) '
return list1 + [d for d in list2 if not d in list1]
def is_intersect(list1, list2):
' True if list1 and list2 have an element in common '
return any(d in list2 for d in list1) or any(d in list1 for d in list2)
# Generate desired result
result = [] # resulting list
for sublist in l1:
if not result or not is_intersect(sublist, result[-1]):
result.append(sublist)
else:
# Intersection with last list, so append to last list in result
result[-1] = append(result[-1], sublist)
print(result)
Output
[[{'id': 1, 'category': 5},
{'id': 3, 'category': 7},
{'id': 4, 'category': 8},
{'id': 6, 'category': 9},
{'id': 9, 'category': 16}],
[{'id': 2, 'category': 4}, {'id': 5, 'category': 17}]]
​
maybe you can try to append the elements into a new list. by doing so, the original list will remain the same and index-out-of-range error wouldn't be raised.
new_list = []
for list in l1:
inner_list = []
for ...
if dictionary in l1[index]:
inner_list.append(list)
...
new_list.append(inner_list)

How to convert list of dict into two lists?

For example:
persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
I want to get two lists from it:
ids = [1, 2, 3]
names = ['john', 'mary', 'tom']
What I did:
names = [d['name'] for d in persons]
ids = [d['id'] for d in persons]
Is there a better way to do it?
I'd stick with using list comprehension or use #Woodford technique
ids,name = [dcts['id'] for dcts in persons],[dcts['name'] for dcts in persons]
output
[1, 2, 3]
['john', 'mary', 'tom']
What you did works fine. Another way to handle this (not necessarily better, depending on your needs) is to store your data in a more efficient dictionary and pull the names/ids out of it when you need them:
>>> persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
>>> p2 = {x['id']: x['name'] for x in persons}
>>> p2
{1: 'john', 2: 'mary', 3: 'tom'}
>>> list(p2.keys())
[1, 2, 3]
>>> list(p2.values())
['john', 'mary', 'tom']
You can do it with pandas in a vectorized fashion:
import pandas as pd
persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
df = pd.DataFrame(persons)
id_list = df.id.tolist() #[1, 2, 3]
name_list = df.name.tolist() #['john', 'mary', 'tom']
An alternative, inspired by this question, is
ids, names = zip(*map(lambda x: x.values(), persons))
that return tuples. If you need lists
ids, names = map(list, zip(*map(lambda x: x.values(), persons)))
It is a little bit slower on my laptop using python3.9 than the accepted answer but it might be useful.
It sounds like you're trying to iterate through the values of your list while unpacking your dictionaries:
persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
for x in persons:
id, name = x.values()
ids.append(id)
names.append(name)

How make list of dict from list of keys and values from list of lists

I have two lists:
first is list of keys,
second is list of values having list.
I want to make list of dictionaries, but I don't know to do that.
keys=['number','type']
values=[[1,2,3,4],['bool','int','float','double']]
I am trying make something, but i am in death point with this.
j=0
for k in keys:
i=0
for v in values[j]:
a=keys[j]
a=a+':'
a=a+str(values[j][i])
print(a)
i=i+1
j=j+1
I want to have output like this:
list=[
{'number':1,'type':'bool'},
{'number':2,'type':'int'},
{'number':3,'type':'float'},
{'number':4,'type':'double'}]
Using list comprehension, zip() and dict(). zip(*values) will yield pairs item from the two sub-lists in values. dict(zip(keys, item)) will produce each dict in the list from tuples, produced by zip(keys, item)
keys=['number','type']
values=[[1,2,3,4],['bool','int','float','double']]
spam = [dict(zip(keys, item)) for item in zip(*values)]
print(spam)
output
[{'number': 1, 'type': 'bool'}, {'number': 2, 'type': 'int'},
{'number': 3, 'type': 'float'}, {'number': 4, 'type': 'double'}]
keys=['number','type']
values=[[1,2,3,4],['bool','int','float','double']]
newList = []
for i in range(len(values[0])):
tmp = {}
for j, key in enumerate(keys):
tmp[key] = values[j][i]
newList.append(tmp)
print(newList)
Output:
[{'number': 1, 'type': 'bool'}, {'number': 2, 'type': 'int'}, {'number': 3, 'type': 'float'}, {'number': 4, 'type': 'double'}]
tip for future: you can use enumerate(list) instead of using i = i+1 or i += 1
out_list = []
for i in range(len(values[0])):
out_list.append({
keys[0]: values[0][i],
keys[1]: values[1][i],
})
print(out_list)
#[{'number': 1, 'type': 'bool'}, {'number': 2, 'type': 'int'}, {'number': 3, 'type': 'float'}, {'number': 4, 'type': 'double'}]
You can also use a list comprehension in combination with zip:
>>> keys = ['number', 'type']
>>> values = [[1, 2, 3, 4],['bool', 'int', 'float', 'double']]
>>> [{keys[0]: number, keys[1]: type} for number, type in zip(*values)]
[{'number': 1, 'type': 'bool'}, {'number': 2, 'type': 'int'}, {'number': 3, 'type': 'float'}, {'number': 4, 'type': 'double'}]

How to Extract Values from Dictionaries and Create Lists From Them

I have a list of dictionaries:
dictionaries = [
{'id': 1, 'name': 'test1', 'description': 'foo'},
{'id': 2, 'name': 'test2', 'description': 'bar'}
]
I would like to separate the values from the keys in each dictionary, making a list of lists like this:
[(1 ,'test1', 'foo'), (2, 'test2', 'bar')]
I have the following code to perform this...
values_list = []
for dict in dictionaries:
values_list.append(list(dict.values()))
When I run this code in my app, I get:
TypeError: list() takes 0 positional arguments but 1 was given
What's the right way to do this type of list comprehension?
That can be done with a couple of comprehensions like:
Code:
def get_values_as_tuple(dict_list, keys):
return [tuple(d[k] for k in keys) for d in dict_list]
How?
How does this work? This is a nested comprehension. Let's go from the inside out, and start with:
tuple(d[k] for k in keys)
This creates a tuple of all of the elements in d that are specified via k in keys. So, that is nice, but what the heck are d, k and keys?
keys is passed to the function, and are the keys we will look for in our dicts.
k is the individual values in keys from k in keys.
d is the individual dicts in dict_list from d in dict_list.
The outer comprehension builds a list of the tuples discussed above:
[tuple(d[k] for k in keys) for d in dict_list]
Test Code:
dictionaries = [{'id': 1, 'name': 'test1', 'description': 'foo'},
{'id': 2, 'name': 'test2', 'description': 'bar'}]
def get_values_as_tuple(dict_list, keys):
return [tuple(d[k] for k in keys) for d in dict_list]
print(get_values_as_tuple(dictionaries, ('id', 'name', 'description')))
Results:
[(1, 'test1', 'foo'), (2, 'test2', 'bar')]
Hi If you want to convert a list of tuples it so easy with list comprehension technique or the code which you are using it is for list of list but you expected solution looks like list of tuples
dictionaries = [{'id': 1, 'name': 'test1', 'description': 'foo'},
{'id': 2, 'name': 'test2', 'description': 'bar'}]
values_list = []
for dict in dictionaries:
values_list.append(tuple(dict.values()))
data = [tuple(dict.values()) for dict in dictionaries]
print(values_list)
print(data)
This might help you which will give you output like this
[(1, 'test1', 'foo'), (2, 'test2', 'bar')]
[(1, 'test1', 'foo'), (2, 'test2', 'bar')]
In [14]: dictionaries = [{'id': 1, 'name': 'test1', 'description':
'foo'},
....: {'id': 2, 'name': 'test2', 'description': 'bar'}]
In [15]: [tuple(d.values()) for d in dictionaries]
Out[15]: [('foo', 1, 'test1'), ('bar', 2, 'test2')]
Hi, Trey,Dict is disordered in python, so the values in the tuple may be disordered too.If you want a ordered result, you may try OrderedDict in python.
In Python 2.x:
from collections import namedtuple
dictionaries = [
{'id': 1, 'name': 'test1', 'description': 'foo'},
{'id': 2, 'name': 'test2', 'description': 'bar'}
]
main_list = []
keys = namedtuple("keys",['id','name','description'])
for val in dictionaries:
data = keys(**val)
main_list.append((data.id,data.name,data.description))
print(main_list)
>>>[(1, 'test1', 'foo'), (2, 'test2', 'bar')]
Python 3.x:
dictionaries = [
{'id': 1, 'name': 'test1', 'description': 'foo'},
{'id': 2, 'name': 'test2', 'description': 'bar'}
]
data = [tuple(val.values()) for val in dictionaries]
print(data)
>>>[(1, 'test1', 'foo'), (2, 'test2', 'bar')]
Code:
dicts = [
{'id': 1, 'name': 'test1', 'description': 'foo'},
{'id': 2, 'name': 'test2', 'description': 'bar'}
]
v_list = []
for d in dicts:
v_list.append( tuple( d.values() ) )
print( v_list )
Results:
[(1, 'test1', 'foo'), (2, 'test2', 'bar')]

How can I update a ValueQuerySet with another ValueQuerySet?

I have the following two ValueQuerySets from Django.
dict1 = [{'user': 1, 'total_bookmarked': 2}, {'user': 2, 'total_bookmarked': 3}]
dict2 = [{'user': 1, 'name': 'Joe'}, {'user': 2, 'name': 'Paula'}]
How can I merge the two ValueQuerySet so that I can get the following:
dict3 = [{'user': 1, 'name': 'Joe', 'total_bookmarked':2}, {'user': 2, 'name': 'Paula', 'total_bookmarked': 3}]
How would I do this? I have thought about converting these back into a Python list of dictionaries, but I'm not sure exactly how to approach it even it that works.
I would first suggest you try to see if you can get this in one query because its more efficient. But if you want to update the first list with the second list, and they are both in the same order:
list1 = [{'user': 1, 'total_bookmarked': 2}, {'user': 2, 'total_bookmarked': 3}]
list2 = [{'user': 1, 'name': 'Joe'}, {'user': 2, 'name': 'Paula'}]
for a,b in zip(list1, list2):
a.update(b)
You can further improve the efficiency if they are very large lists by using izip
from itertools import izip
for a,b in izip(list1, list2):
a.update(b)
And if for some reason they are not both already sorted by user:
from operator import itemgetter
list1.sort(key=itemgetter('user'))
list2.sort(key=itemgetter('user'))
I would avoid a solution that uses nested for-loops, as it won't be as efficient.
If they were just unordered lists or dictionaries it would be
list1 = [{'user': 1, 'total_bookmarked': 2}, {'user': 2, 'total_bookmarked': 3}]
list2 = [{'user': 1, 'name': 'Joe'}, {'user': 2, 'name': 'Paula'}]
list3 = []
for d1 in list1:
for d2 in list2:
if d1['user'] == d2['user']:
d3 = dict(d1.items()+d2.items()
list3.append(d3)
break
else:
continue
There is a much better way if your lists are ordered by user
list1 = [{'user': 1, 'total_bookmarked': 2}, {'user': 2, 'total_bookmarked': 3}]
list2 = [{'user': 1, 'name': 'Joe'}, {'user': 2, 'name': 'Paula'}]
list3 = [dict(d1.items()+d2.items()) for (d1, d2) in zip(list1,list2)]

Categories