How to convert this loops into list comprehension? - python

I want to convert these loops into a list comprehension but I don't know how to do it. Can anyone help me pls?
this is the list i want to convert:
students = ['Tommy', 'Kitty', 'Jessie', 'Chester', 'Curie', 'Darwing', 'Nancy', 'Sue',
'Peter', 'Andrew', 'Karren', 'Charles', 'Nikhil', 'Justin', 'Astha','Victor',
'Samuel', 'Olivia', 'Tony']
assignment = [2, 5, 5, 7, 1, 5, 2, 7, 5, 1, 1, 1, 2, 1, 5, 2, 7, 2, 7]
x = list(zip(students, assignment))
Output = {}
for ke, y in x:
y = "Group {}".format(y)
if y in Output:
Output[y].append((ke))
else:
Output[y] = [(ke)]
print(Output)
this what I have tried:
{Output[y].append((ke)) if y in Output else Output[y]=[(ke)]for ke, y in x}

You could do this with a nested dictionary/list comprehension:
Output = { f'Group {group}' : [ name for name, g in x if g == group ] for group in set(assignment) }
Output:
{
'Group 2': ['Tommy', 'Nancy', 'Nikhil', 'Victor', 'Olivia'],
'Group 5': ['Kitty', 'Jessie', 'Darwing', 'Peter', 'Astha'],
'Group 7': ['Chester', 'Sue', 'Samuel', 'Tony'],
'Group 1': ['Curie', 'Andrew', 'Karren', 'Charles', 'Justin']
}

data1 = {'students': ['Tommy', 'Kitty', 'Jessie', 'Chester', 'Curie', 'Darwing', 'Nancy', 'Sue',
'Peter', 'Andrew', 'Karren', 'Charles', 'Nikhil', 'Justin', 'Astha','Victor',
'Samuel', 'Olivia', 'Tony'],
'assignment': [2, 5, 5, 7, 1, 5, 2, 7, 5, 1, 1, 1, 2, 1, 5, 2, 7, 2, 7]}
df1 = pd.DataFrame(data1)
df1.groupby('assignment')['students'].agg(set).to_dict()
Output
{1: {'Andrew', 'Charles', 'Curie', 'Justin', 'Karren'},
2: {'Nancy', 'Nikhil', 'Olivia', 'Tommy', 'Victor'},
5: {'Astha', 'Darwing', 'Jessie', 'Kitty', 'Peter'},
7: {'Chester', 'Samuel', 'Sue', 'Tony'}}

You want a dict comprehension which will create a dict whose values come from a list comprehension.
itertools.groupby can help:
from itertools import groupby
x = sorted(list(zip(assignment, students)))
out = {f'Group {x}':[z[1] for z in y] for x,y in groupby(x, lambda y:y[0])}
{'Group 1': ['Andrew', 'Charles', 'Curie', 'Justin', 'Karren'], 'Group 2': ['Nancy', 'Nikhil', 'Olivia', 'Tommy', 'Victor'], 'Group 5': ['Astha', 'Darwing', 'Jessie', 'Kitty', 'Peter'], 'Group 7': ['Chester', 'Samuel', 'Sue', 'Tony']}

Related

How to convert key to value in dictionary type?

I have a question about the convert key.
First, I have this type of word count in Data Frame.
[Example]
dict = {'forest': 10, 'station': 3, 'office': 7, 'park': 2}
I want to get this result.
[Result]
result = {'name': 'forest', 'value': 10,
'name': 'station', 'value': 3,
'name': 'office', 'value': 7,
'name': 'park', 'value': 2}
Please check this issue.
As Rakesh said:
dict cannot have duplicate keys
The closest way to achieve what you want is to build something like that
my_dict = {'forest': 10, 'station': 3, 'office': 7, 'park': 2}
result = list(map(lambda x: {'name': x[0], 'value': x[1]}, my_dict.items()))
You will get
result = [
{'name': 'forest', 'value': 10},
{'name': 'station', 'value': 3},
{'name': 'office', 'value': 7},
{'name': 'park', 'value': 2},
]
As Rakesh said, You can't have duplicate values in the dictionary
You can simply try this.
dict = {'forest': 10, 'station': 3, 'office': 7, 'park': 2}
result = {}
count = 0;
for key in dict:
result[count] = {'name':key, 'value': dict[key]}
count = count + 1;
print(result)

Problem inputting several lists to dictionary values

Stackoverflow, hello
I have a big problem with inputting a several list into multiple values
Initial code is:
animal_book={}
animal_type=['herbivorous', 'carnivorous']
animal_name=[['Elephant', 'Cow', 'Deer'], ['Tiger', 'Lion', 'Puma']]
animal_quantity=[[1, 2, 3], [4, 5, 6]]
animal_age=[['50','10','5'],['6', '7', '8']]
j=0
k=0
for i in animal_type:
animal_book[i]=[{'type':animal_name[j][k], 'name': animal_quantity[j][k], 'age':animal_age[j][k]}]
j += 1
print(animal_book)
The result I have is almost what I need, but with only one first compound in a animal_book value, not the several dictionaries, as I wanted (I've separated it by lines manually for better look):
>>{'herbivorous': [
{'name': 'Elephant', 'quantity': 1, 'age': '50'}
],
'carnivorous': [
{'name': 'Tiger', 'quantity': 4, 'age': '6'}
]
}
However, my aim here is to put these list into multiple values of the dictionary. Required code is:
{'herbivorous': [
{'name': 'Elephant', 'quantity': 1, 'age': '50'},
{'name': 'Cow', 'quantity': 2, 'age': '10'},
{'name': 'Deer', 'quantity': 3, 'age': '5'},
],
'carnivorous':[
{'name': 'Tiger', 'quantity': 4, 'age': '6'}
{'name': 'Lion', 'quantity': 5, 'age': '7'}
{'name': 'Puma', 'quantity': 6, 'age': '8'}
]
}
Does everybody know how to solve the problem?
I've tried to add the lists to animal_book.values() also after the for i in animal_type:
animal_book[i]=animal_book.values().append([{'name':animal_name[j][k], 'quantity': animal_quantity[j][k], 'age':animal_age[j][k]}])
But in this case I have an error: AttributeError: 'dict_values' object has no attribute 'append'
First Mistake :you are getting only one result because you are over-writing the dictionary value each time with the list .
Second Mistake : You are increasing j by one and looping through the animal type list which has 2 elements that means only two elements will be in the dictionary.
from pprint import pprint
animal_book={}
animal_type=['herbivorous', 'carnivorous']
animal_name=[['Elephant', 'Cow', 'Deer'], ['Tiger', 'Lion', 'Puma']]
animal_quantity=[[1, 2, 3], [4, 5, 6]]
animal_age=[['50','10','5'],['6', '7', '8']]
for j in range(len(animal_type)):
value_list = []
for k in range(len(animal_name[j])):
value_list.append({'type':animal_quantity[j][k], 'name': animal_name[j][k], 'age':animal_age[j][k]})
animal_book.update({animal_type[j]: value_list})
pprint(animal_book)
Output:
{'carnivorous': [{'age': '6', 'name': 'Tiger', 'type': 4},
{'age': '7', 'name': 'Lion', 'type': 5},
{'age': '8', 'name': 'Puma', 'type': 6}],
'herbivorous': [{'age': '50', 'name': 'Elephant', 'type': 1},
{'age': '10', 'name': 'Cow', 'type': 2},
{'age': '5', 'name': 'Deer', 'type': 3}]}
You can use zip to arrange your data in a suiteable manner and fill your book with that:
animal_book ={}
animal_type=['herbivorous', 'carnivorous']
animal_name=[['Elephant', 'Cow', 'Deer'], ['Tiger', 'Lion', 'Puma']]
animal_quantity=[[1, 2, 3], [4, 5, 6]]
animal_age=[['50','10','5'],['6', '7', '8']]
# zip your data together, extract the typ again, put the remainder into R
for typ, *R in zip(animal_type, animal_name, animal_quantity, animal_age):
# add the typ-list
animal_book.setdefault(typ,[])
# now handle the inner dicts data that have to be added to your lists
# first create tuples for each animal as r
for r in zip(*R):
# then create tuples of (key,value) and make dicts from it
animal_book[typ].append(dict(zip(["name","quantity","age"],r)))
# pretty print it
from pprint import pprint
pprint(animal_book)
Output:
{'carnivorous': [{'age': '6', 'name': 'Tiger', 'quantity': 4},
{'age': '7', 'name': 'Lion', 'quantity': 5},
{'age': '8', 'name': 'Puma', 'quantity': 6}],
'herbivorous': [{'age': '50', 'name': 'Elephant', 'quantity': 1},
{'age': '10', 'name': 'Cow', 'quantity': 2},
{'age': '5', 'name': 'Deer', 'quantity': 3}]}
R looks like this:
[['Elephant', 'Cow', 'Deer'], [1, 2, 3], ['50', '10', '5']]
[['Tiger', 'Lion', 'Puma'], [4, 5, 6], ['6', '7', '8']]
and r look like this:
('Elephant', 1, '50')
('Cow', 2, '10')
('Deer', 3, '5')
('Tiger', 4, '6')
('Lion', 5, '7')
('Puma', 6, '8')
and zip(["name","quantity","age"],r) looks approximately like so:
[('name', 'Elephant'), ('quantity', 1), ('age', '50')]
[('name', 'Cow'), ('quantity', 2), ('age', '10')]
[('name', 'Deer'), ('quantity', 3), ('age', '5')]
[('name', 'Tiger'), ('quantity', 4), ('age', '6')]
[('name', 'Lion'), ('quantity', 5), ('age', '7')]
[('name', 'Puma'), ('quantity', 6), ('age', '8')]
Here you go, this solves your problem. You have to have one for loop nested inside another one and use enumerate so you can keep track of the index. Also, if you use json.dumps() it will pretty-print a dictionary for you.
import json
animal_type=['herbivorous', 'carnivorous']
animal_name=[['Elephant', 'Cow', 'Deer'], ['Tiger', 'Lion', 'Puma']]
animal_quantity=[[1, 2, 3], [4, 5, 6]]
animal_age=[['50','10','5'],['6', '7', '8']]
animal_book={}
for index, type in enumerate(animal_type):
animal_book[type] = []
for jdex, animal in enumerate(animal_name[index]):
animal_book[type].append({
'name': animal,
'quantity': animal_quantity[index][jdex],
'age': animal_age[index][jdex],
})
print(json.dumps(animal_book, indent=2))
This will output:
{
"herbivorous": [
{
"name": "Elephant",
"quantity": 1,
"age": "50"
},
{
"name": "Cow",
"quantity": 2,
"age": "10"
},
{
"name": "Deer",
"quantity": 3,
"age": "5"
}
],
"carnivorous": [
{
"name": "Tiger",
"quantity": 4,
"age": "6"
},
{
"name": "Lion",
"quantity": 5,
"age": "7"
},
{
"name": "Puma",
"quantity": 6,
"age": "8"
}
]
}
You should use the range function to iterate over the items in more systematic way:
animal_book={}
animal_type=['herbivorous', 'carnivorous']
animal_name=[['Elephant', 'Cow', 'Deer'], ['Tiger', 'Lion', 'Puma']]
animal_quantity=[[1, 2, 3], [4, 5, 6]]
animal_age=[['50','10','5'],['6', '7', '8']]
for i in range(len(animal_type)):
for j in range(len(animal_name[i])):
animal_book[i]=[{'type':animal_name[i][j], 'name': animal_quantity[i][j], 'age':animal_age[i][j]}]
print(animal_book)

Combining multiple lists of dictionaries

I have several lists of dictionaries, where each dictionary contains a unique id value that is common among all lists. I'd like to combine them into a single list of dicts, where each dict is joined on that id value.
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
I tried doing something like the answer found at https://stackoverflow.com/a/42018660/7564393, but I'm getting very confused since I have more than 2 lists. Should I try using a defaultdict approach? More importantly, I am NOT always going to know the other values, only that the id value is present in all dicts.
You can use itertools.groupby():
from itertools import groupby
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = []
for _, values in groupby(sorted([*list1, *list2, *list3], key=lambda x: x['id']), key=lambda x: x['id']):
temp = {}
for d in values:
temp.update(d)
desired_output.append(temp)
Result:
[{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
# combine all lists
d = {} # id -> dict
for l in [list1, list2, list3]:
for list_d in l:
if 'id' not in list_d: continue
id = list_d['id']
if id not in d:
d[id] = list_d
else:
d[id].update(list_d)
# dicts with same id are grouped together since id is used as key
res = [v for v in d.values()]
print(res)
You can first build a dict of dicts, then turn it into a list:
from itertools import chain
from collections import defaultdict
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
dict_out = defaultdict(dict)
for d in chain(list1, list2, list3):
dict_out[d['id']].update(d)
out = list(dict_out.values())
print(out)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
itertools.chain allows you to iterate on all the dicts contained in the 3 lists. We build a dict dict_out having the id as key, and the corresponding dict being built as value. This way, we can easily update the already built part with the small dict of our current iteration.
Here, I have presented a functional approach without using itertools (which is excellent in rapid development work).
This solution will work for any number of lists as the function takes variable number of arguments and also let user to specify the type of return output (list/dict).
By default it returns list as you want that otherwise it returns dictionary in case if you pass as_list = False.
I preferred dictionary to solve this because its fast and search complexity is also less.
Just have a look at the below get_packed_list() function.
get_packed_list()
def get_packed_list(*dicts_lists, as_list=True):
output = {}
for dicts_list in dicts_lists:
for dictionary in dicts_list:
_id = dictionary.pop("id") # id() is in-built function so preferred _id
if _id not in output:
# Create new id
output[_id] = {"id": _id}
for key in dictionary:
output[_id][key] = dictionary[key]
dictionary["id"] = _id # push back the 'id' after work (call by reference mechanism)
if as_list:
return [output[key] for key in output]
return output # dictionary
Test
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
output = get_packed_list(list1, list2, list3)
print(output)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
output = get_packed_list(list1, list2, list3, as_list=False)
print(output)
# {1: {'id': 1, 'value': 20, 'sum': 10, 'total': 30}, 2: {'id': 2, 'value': 21, 'sum': 11, 'total': 32}}
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
print(list1+list2+list3)
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
result = []
for i in range(0,len(list1)):
final_dict = dict(list(list1[i].items()) + list(list2[i].items()) + list(list3[i].items()))
result.append(final_dict)
print(result)
output : [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]

Separate list elements by theirs property in Python

I have list p1:
p1 = [
{'id': 1, 'area': 5},
{'id': 2, 'area': 6},
{'id': 3, 'area': 10},
{'id': 4, 'area': 6},
{'id': 5, 'area': 6},
{'id': 6, 'area': 6},
{'id': 7, 'area': 4},
{'id': 8, 'area': 4}
]
And I need to separate this list by area value, like this (p2):
p2 = {
4: [
{'id': 7, 'area': 4},
{'id': 8, 'area': 4}
],
5: [
{'id': 1, 'area': 5}
],
6: [
{'id': 2, 'area': 6},
{'id': 4, 'area': 6},
{'id': 5, 'area': 6},
{'id': 6, 'area': 6}
],
10: [
{'id': 3, 'area': 10}
]
}
My solution is:
areas = {x['area'] for x in p1}
p2 = {}
for area in areas:
p2[area] = [x for x in p1 if x['area'] == area]
It seems to work, but is there any better and more "pythonic" solution?
Using groupby you get
>>> import itertools
>>> f = lambda t: t['area']
>>> {i: list(b) for i, b in itertools.groupby(sorted(p1, key=f), key=f)}
Gives
{4: [{'area': 4, 'id': 7},
{'area': 4, 'id': 8}],
5: [{'area': 5, 'id': 1}],
6: [{'area': 6, 'id': 2},
{'area': 6, 'id': 4},
{'area': 6, 'id': 5},
{'area': 6, 'id': 6}],
10: [{'area': 10, 'id': 3}]}
edit: If you don't like using lambdas you can also do, as suggested by bro-grammer
>>> import operator
>>> f = operator.itemgetter('area')
You can simply use defaultdict:
from collections import defaultdict
result = defaultdict(list)
for i in p1:
result[i['area']].append(i)
Yes, use one of the grouping idioms. Using a vanilla dict:
In [15]: p1 = [
...: {'id': 1, 'area': 5},
...: {'id': 2, 'area': 6},
...: {'id': 3, 'area': 10},
...: {'id': 4, 'area': 6},
...: {'id': 5, 'area': 6},
...: {'id': 6, 'area': 6},
...: {'id': 7, 'area': 4},
...: {'id': 8, 'area': 4}
...: ]
In [16]: p2 = {}
In [17]: for d in p1:
...: p2.setdefault(d['area'], []).append(d)
...:
In [18]: p2
Out[18]:
{4: [{'area': 4, 'id': 7}, {'area': 4, 'id': 8}],
5: [{'area': 5, 'id': 1}],
6: [{'area': 6, 'id': 2},
{'area': 6, 'id': 4},
{'area': 6, 'id': 5},
{'area': 6, 'id': 6}],
10: [{'area': 10, 'id': 3}]}
Or more neatly, using a defaultdict:
In [23]: from collections import defaultdict
In [24]: p2 = defaultdict(list)
In [25]: for d in p1:
...: p2[d['area']].append(d)
...:
In [26]: p2
Out[26]:
defaultdict(list,
{4: [{'area': 4, 'id': 7}, {'area': 4, 'id': 8}],
5: [{'area': 5, 'id': 1}],
6: [{'area': 6, 'id': 2},
{'area': 6, 'id': 4},
{'area': 6, 'id': 5},
{'area': 6, 'id': 6}],
10: [{'area': 10, 'id': 3}]})

Python controlling the output "print"

all_path = [[[2, 3, 4, 5], [2, 4, 5], [2, 5]],
[[2, 3, 4, 5], [2, 4, 5], [2, 5]],
[[2, 3, 4, 5], [2, 4, 5], [2, 5]],
[[4, 5]],
[[1, 2, 3, 4, 5], [1, 2, 4, 5], [1, 2, 5]]]
s_dict = {1: {'Origin': '002', 'Destination': '005', 'Cost': '0000.00', 'Stops': '99', 'Time': '00.00'},
2: {'Origin': '002', 'Destination': '005', 'Cost': '0000.00', 'Stops': '11', 'Time': '00.00'},
3: {'Origin': '002', 'Destination': '005', 'Cost': '1450.11', 'Stops': '99', 'Time': '00.00'},
4: {'Origin': '004', 'Destination': '005', 'Cost': '1550.11', 'Stops': '99', 'Time': '22.22'},
5: {'Origin': '001', 'Destination': '005', 'Cost': '0000.00', 'Stops': '99', 'Time': '11.00'}}
for tin in range(1,6):
print 'From: '+str(int(s_dict[tin]['Origin']))+','+' to: '+str(int((s_dict[tin]['Destination'])))+','+' Stops: '+(s_dict[tin]['Stops'])+','+' Cost: '+(s_dict[tin]['Cost'])+','+' Time: '+(s_dict[tin]['Time'])
print 'All routes:'
for n in range(len(all_path[tin-1])):
l=''
for s in range(len(all_path[tin-1][n])):
l+= str(all_path[tin-1][n][s])+'->'
print l
and this is the output,
I will quote one part
From: 2, to: 5, Stops: 99, Cost: 0000.00, Time: 00.00
All routes:
2->3->4->5->
2->4->5->
2->5->
my problem is that extra ' -> '
at the end of the line
I want it to be something more like
2->3->4->5
is there a way to not show "an extra" ' -> ' at the end?
Take a look at the join-method:
print '->'.join(str(x) for x in all_path[tin-1][n])
# print '->'.join(map(str, all_path[tin-1][n]))
> print '->'.join(['1', '2', '3']) # '->'.join('123')
1->2->3

Categories