I have 2 lists, both of which aren't fixed in len.
list1 = ["John", "bruce", "William"]
list2 = ["lindt", "reese", "snickers", "chocolate", "Milkyway", "Cadbury", "Candy"]
I want to distribute the candy amongst the members in list1 so that end result would look something like
John: "lindt","chocolate","candy"
Bruce: "reese","Mlikyway"
Will: "Snickers","Cadbury"
I tried using cycle and zip from itertools but all I am getting is a tuple with something like
list1 = ["John","bruce","William"]
list2 = ["lindt","reese","snickers","chocolate","Milkyway","Cadbury","Candy"]
for i in zip(list2,cycle(list1)):
print(i)
Output
('lindt', 'John')
('reese', 'bruce')
('snickers', 'William')
('chocolate', 'John')
('Milkyway', 'bruce')
('Cadbury', 'William')
('Candy', 'John')
Let's use a dictionary:
kids = {}
all members from list1 become a list in your dictionary:
for i in list1: kids[i] = []
then use zip and cycle to assign each kid their candy:
for i in zip(list2,cycle(list1)): kids[i[1]].append(i[0])
# kids[i[1]] represents the kids's name since it's at index 1 in the tuple
# i[0] represents the candy that is associated to the kid.
Result:
>>> for i in kids: print(i,':', kids[i])
john : ['lindt', 'chocolate', 'candy']
bruce : ['reese', 'milkyway']
william : ['snickers', 'cadbury']
You were pretty close but you need a data structure to store these results. Instead of creating a dictionary containing the keys and empty lists you can also use dict.setdefault:
from itertools import cycle
d = dict()
for name, item in zip(cycle(list1), list2):
d.setdefault(name, []).append(item)
print(d)
# {'John': ['lindt', 'chocolate', 'Candy'],
# 'William': ['snickers', 'Cadbury'],
# 'bruce': ['reese', 'Milkyway']}
Instead of setdefault you can also use collections.defaultdict:
from itertools import cycle
from collections import defaultdict
d = defaultdict(list)
for name, item in zip(cycle(list1), list2):
d[name].append(item)
print(d)
# defaultdict(list,
# {'John': ['lindt', 'chocolate', 'Candy'],
# 'William': ['snickers', 'Cadbury'],
# 'bruce': ['reese', 'Milkyway']})
Related
I get a list here:
my_list=["Alex:1990:London",
"Tony:1993:NYC",
"Kate:2001:Beijing",
"Tony:2001:LA",
"Alex:1978:Shanghai"]
How can I get the target dictionary my_target_dict from my_list in the easiest way?
my_target_dict={
"Alex":["Alex:1990:London", "Alex:1978:Shanghai"],
"Tony":["Tony:1993:NYC", "Tony:2001:LA"],
"Kate":["Kate:2001:Beijing"]
}
Use a defaultdict:
>>> from collections import defaultdict
>>> my_list=["Alex:1990:London", "Tony:1993:NYC", "Kate:2001:Beijing", "Tony:2001:LA", "Alex:1978:Shanghai"]
>>> d = defaultdict(list)
>>> for item in my_list:
... name, *_ = item.partition(":")
... d[name].append(item)
...
>>> d
defaultdict(<class 'list'>, {'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': ['Kate:2001:Beijing']})
>>> d["Alex"]
['Alex:1990:London', 'Alex:1978:Shanghai']
You can use this comprehension to clean the list wrapped single items:
>>> {k:v if len(v) > 1 else v[0] for k,v in d.items()}
{'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': 'Kate:2001:Beijing'}
In case you intend to work strictly with lists and dictionaries alone, try this:
my_target_dict=dict()
for value in my_list:
key=value.split(':')[0]
if key in my_target_dict:
my_target_dict[key].append(value)
else:
my_target_dict[key]=[value]
print(my_target_dict)
This is my solution for you:
my_list=["Alex:1990:London", "Tony:1993:NYC", "Kate:2001:Beijing", "Tony:2001:LA", "Alex:1978:Shanghai"]
dict = {}
for idx, content in enumerate(my_list):
name = content[:(content.index(':'))]
if name not in dict:
dict[name] = []
dict[name].append(my_list[idx])
First if you don't know about enumerate, it count your index and
take the content in each element of list.
Second, take name of there people by basic python of string. I use name = content[:(content.index(':'))] in order to take string from start to the first symbol ":".
Third, check if the key of dict exist or not. Otherwise, it will delete all your element in list of that key.
Last but not least, append the element you want into your key dict.
Your finally result:
{'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': ['Kate:2001:Beijing']}
If you are a beginner (as I see) and don't want to use Python's collections module and do the implementation from scratch (it's imp to understand the concept of background work which collection does).
Once you are familiar with this, you can go with collections module and that is beautiful as it has many classes like defaultdict, OrderedDict etc. which can boost the speed of your work.
Here is what I have tried (do not forget to read the commented lines).
I have written a function named get_my_target_dict() which takes my_list and returns my_target_dict. And this is the modular implemenation (that you should prefer).
re is a module to work with regular expressions. Here it is used to match "Alex: 1990 : London" (i.e. spaces around :) kind of strings if any (by mistake).
import re
def get_my_target_dict(my_list):
my_target_dict = {} # dictionary
for string in my_list:
# "Alex:1990:London" => ["Alex", "1990", "London"]
# "Alex : 1990: London" => ["Alex", "1990", "London"]
items = re.split(r"\s*:\s*", string) # `\s*` is to match spaces around `:`
print(items)
# Alex, Tony etc.
key = items[0]
if key in my_target_dict:
my_target_dict[key].append(string)
else:
my_target_dict[key] = [string]
return my_target_dict
if __name__ == "__main__":
my_list=["Alex:1990:London",
"Tony:1993:NYC",
"Kate:2001:Beijing",
"Tony:2001:LA",
"Alex:1978:Shanghai"]
# Call get_my_target_dict(), pass my_list & get my_target_dict
my_target_dict = get_my_target_dict(my_list)
print(my_target_dict)
# {'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': ['Kate:2001:Beijing']}
# Pretty printing dictionary
import json
print(json.dumps(my_target_dict, indent=4))
# {
# "Alex": [
# "Alex:1990:London",
# "Alex:1978:Shanghai"
# ],
# "Tony": [
# "Tony:1993:NYC",
# "Tony:2001:LA"
# ],
# "Kate": [
# "Kate:2001:Beijing"
# ]
# }
How to merge a tuple with the same key
list_1 = [("AAA", [123]), ("AAA", [456]), ("AAW", [147]), ("AAW", [124])]
and turn them into
list_2 = [("AAA", [123, 456]), ("AAW", [147, 124])]
The most performant approach is to use a collections.defaultdict dictionary to store data as an expanding list, then convert back to tuple/list if needed:
import collections
list_1 = [("AAA", [123]), ("AAA", [456]), ("AAW", [147]), ("AAW", [124])]
c = collections.defaultdict(list)
for a,b in list_1:
c[a].extend(b) # add to existing list or create a new one
list_2 = list(c.items())
result:
[('AAW', [147, 124]), ('AAA', [123, 456])]
note that the converted data is probably better left as dictionary. Converting to list again loses the "key" feature of the dictionary.
On the other hand, if you want to retain the order of the "keys" of the original list of tuples, unless you're using python 3.6/3.7, you'd have to create a list with the original "keys" (ordered, unique), then rebuild the list from the dictionary. Or use an OrderedDict but then you cannot use defaultdict (or use a recipe)
You can use a dict to keep track of the indices of each key to keep the time complexity O(n):
list_1 = [("AAA", [123]), ("AAA", [456]), ("AAW", [147]), ("AAW", [124])]
list_2 = []
i = {}
for k, s in list_1:
if k not in i:
list_2.append((k, s))
i[k] = len(i)
else:
list_2[i[k]][1].extend(s)
list_2 would become:
[('AAA', [123, 456]), ('AAW', [147, 124])]
You can create a dictionary and loop through the list. If the item present in dictionary append the value to already existing list else assign the value to key.
dict_1 = {}
for item in list_1:
if item[0] in dict_1:
dict_1[item[0]].append(item[1][0])
else:
dict_1[item[0]] = item[1]
list_2 = list(dict_1.items())
Similarly to other answers, you can use a dictionary to associate each key with a list of values. This is implemented in the function merge_by_keys in the code snippet below.
import pprint
list_1 = [("AAA", [123]), ("AAA", [456]), ("AAW", [147]), ("AAW", [124])]
def merge_by_key(ts):
d = {}
for t in ts:
key = t[0]
values = t[1]
if key not in d:
d[key] = values[:]
else:
d[key].extend(values)
return d.items()
result = merge_by_key(list_1)
pprint.pprint(result)
I have dataset like this:
{'project-1': [{'id':'1','name':'john'},{'id':'20','name':'steve'}],
'project-2': [{'id':'6','name':'jack'},{'id':'42','name':'anna'}]}
what I want to extract is the name of all people:
['john','steve','jack','anna']
How to get these list using python?
my_dict = {
'project-1': [{'id':'1','name':'john'},{'id':'20','name':'steve'}],
'project-2': [{'id':'6','name':'jack'},{'id':'42','name':'anna'}]
}
You can use a list comprehension it get the name field from each dictionary contained within the sublists (i.e. within the values of the original dictionary).
>>> [d.get('name') for sublists in my_dict.values() for d in sublists]
['john', 'steve', 'jack', 'anna']
Iterate over the dict, then over the values of the current dict:
for d_ in d.values():
for item in d_:
print item['name']
Or in comprehension
names = [item['name'] for d_ in d.values() for item in d_]
print names
['john', 'steve', 'jack', 'anna']
This should do it.
d = {'project-1': [{'id':'1','name':'john'},{'id':'20','name':'steve'}],
'project-2': [{'id':'6','name':'jack'},{'id':'42','name':'anna'}]}
result = list()
for key in d:
for x in d[key]:
result.append(x['name'])
Many solutions trying same old approach here using two loop:
Here is different approach:
One line solution without any loop:
You can use lambda function with map:
data={'project-1': [{'id':'1','name':'john'},{'id':'20','name':'steve'}],
'project-2': [{'id':'6','name':'jack'},{'id':'42','name':'anna'}]}
print(list(map(lambda x:list(map(lambda y:y['name'],x)),data.values())))
output:
[['john', 'steve'], ['jack', 'anna']]
name_id = {'project-1': [{'id':'1','name':'john'},{'id':'20','name':'steve'}], 'project-2': [{'id':'6','name':'jack'},{'id':'42','name':'anna'}]}
name_id['project-1'][0]['name'] = 'john'
name_id['project-1'][1]['name'] = 'steve'
name_id['project-2'][0]['name'] = 'jack'
name_id['project-2'][1]['name'] = 'anna'
The ['project-1'] gets the value corresponding to the project-1 key in the dictionary name_id. [0] is the list index for the first element in the dictionary value. ['name'] is also a key, but of the dictionary in the first element of the list. It gives you the final value that you want.
list1 = ['fire', 'cats', 'mats', 'wats', 'mire', 'tire']
I would like to divide these words up based on the 3 last letters of each word, and save it into a dictionary.
Is this possible?
Create a defaultdict with list as default item, and append items, computing key with string slice, like this:
import collections
list1 = ['fire', 'cats', 'mats', 'wats', 'mire', 'tire']
d=collections.defaultdict(list)
for i in list1:
d[i[-3:]].append(i)
print(dict(d)) # copy in a dict just for clean display (no defaultdict prefix)
result:
{'ire': ['fire', 'mire', 'tire'], 'ats': ['cats', 'mats', 'wats']}
Also can be done with a one-liner, not as efficient because of the inner loo which tests all the list (one-liners are trendy, but sometimes just not the best solution):
d = {k:[v for v in list1 if v.endswith(k)] for k in set(x[-3:] for x in list1)}
result:
{'ire': ['fire', 'mire', 'tire'], 'ats': ['cats', 'mats', 'wats']}
if you wanted to filter out items with not enough associated words you could do this (after having computed d in the first pass):
d = {k:v for k,v in d.items() if len(v)>2}
that creates a new dictionary with only key/values if there are more than 2 elements.
I have the following Python list:
list1 = ['EW:G:B<<LADHFSSFAFFF', 'CB:E:OWTOWTW', 'PP:E:A,A<F<AF', 'GR:A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7', 'SX:F:-111', 'DS:f:115.5', 'MW:AA:0', 'MA:A:0XT:i:0', 'EY:EE:KJERWEWERKJWE']
I would like to take the entries of this list and create a dictionary of key-values pairs that looks like
dictionary_list1 = {'EW':'G:B<<LADHFSSFAFFF', 'CB':'E:OWTOWTW', 'PP':'E:A,A<F<AF', 'GR':'A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7', 'SX':'F:-111', 'DS':'f:115.5', 'MW':'AA:0', 'MA':'A:0XT:i:0', 'EW':'EE:KJERWEWERKJWE'}
How does one parse/split the list above list1 to do this? My first instinct was to try try1 = list1.split(":"), but then I think it is impossible to retrieve the "key" for this list, as there are multiple colons :
What is the most pythonic way to do this?
You can specify a maximum number of times to split with the second argument to split.
list1 = ['EW:G:B<<LADHFSSFAFFF', 'CB:E:OWTOWTW', 'PP:E:A,A<F<AF', 'GR:A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7', 'SX:F:-111', 'DS:f:115.5', 'MW:AA:0', 'MA:A:0XT:i:0', 'EW:EE:KJERWEWERKJWE']
d = dict(item.split(':', 1) for item in list1)
Result:
>>> import pprint
>>> pprint.pprint(d)
{'CB': 'E:OWTOWTW',
'DS': 'f:115.5',
'EW': 'EE:KJERWEWERKJWE',
'GR': 'A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7',
'MA': 'A:0XT:i:0',
'MW': 'AA:0',
'PP': 'E:A,A<F<AF',
'SX': 'F:-111'}
If you'd like to keep track of values for non-unique keys, like 'EW:G:B<<LADHFSSFAFFF' and 'EW:EE:KJERWEWERKJWE', you could add keys to a collections.defaultdict:
import collections
d = collections.defaultdict(list)
for item in list1:
k,v = item.split(':', 1)
d[k].append(v)
Result:
>>> pprint.pprint(d)
{'CB': ['E:OWTOWTW'],
'DS': ['f:115.5'],
'EW': ['G:B<<LADHFSSFAFFF', 'EE:KJERWEWERKJWE'],
'GR': ['A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7'],
'MA': ['A:0XT:i:0'],
'MW': ['AA:0'],
'PP': ['E:A,A<F<AF'],
'SX': ['F:-111']}
You can also use str.partition
list1 = ['EW:G:B<<LADHFSSFAFFF', 'CB:E:OWTOWTW', 'PP:E:A,A<F<AF', 'GR:A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7', 'SX:F:-111', 'DS:f:115.5', 'MW:AA:0', 'MA:A:0XT:i:0', 'EW:EE:KJERWEWERKJWE']
d = dict([t for t in x.partition(':') if t!=':'] for x in list1)
# or more simply as TigerhawkT3 mentioned in the comment
d = dict(x.partition(':')[::2] for x in list1)
for k, v in d.items():
print('{}: {}'.format(k, v))
Output:
MW: AA:0
CB: E:OWTOWTW
GR: A:OUO-1-XXX-EGD:forthyFive:1:HMJeCXX:7
PP: E:A,A<F<AF
EW: EE:KJERWEWERKJWE
SX: F:-111
DS: f:115.5
MA: A:0XT:i:0