I have two python lists:
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
The "keys" are cluster ID list for the corresponding words in "values" list. I wish to print key-value pairs using
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
dictionary = dict(zip(keys, values))
for key, value in dictionary.items() :
print (key, value)
But it only prints
1 apple
2 paper
3 tennis
What I actually want is to get all values for all keys like this
1 [apple]
2 [book,pen,paper]
3 [soccer,tennis]
I know that my current code should logically print the first output as keys are unique. But how can I change it so that it will print all values for all keys? Thank you in advance!
from collections import defaultdict
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
d = defaultdict(list)
for k, v in zip(keys, values):
d[k].append(v)
Looks like what you want is a mapping from one key to multiple values, one way to accomplish it would be:
from collections import defaultdict
d = defaultdict(list)
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
for tuple in zip(keys, values):
d[tuple[0]].append(tuple[1])
print(d) # defaultdict(<class 'list'>, {1: ['apple'], 2: ['book', 'pen', 'paper'], 3: ['soccer', 'tennis']})
You can use itertools:
import itertools
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
final_data = {a:[i[0] for i in b] for a, b in [(a, list(b)) for a, b in itertools.groupby(sorted(zip(values, keys), key=lambda x:x[-1]), key=lambda x:x[-1])]}
Output:
{1: ['apple'], 2: ['book', 'pen', 'paper'], 3: ['soccer', 'tennis']}
pure python also works
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
d = dict(zip(keys, [[] for _ in keys])) # dict w keys, empty lists as values
for k, v in zip(keys, values):
d[k].append(v)
d
Out[128]: {1: ['apple'], 2: ['book', 'pen', 'paper'], 3: ['soccer', 'tennis']}
Two method :
If you want you can use default dict as many already have been suggested :
Data is :
keys=[1,2,2,3,2,3]
values=['apple','book','pen','soccer','paper','tennis']
Method: 1
import collections
d=collections.defaultdict(list)
for i in zip(keys,values):
d[i[0]].append(i[1])
print(d)
output:
{1: ['apple'], 2: ['book', 'pen', 'paper'], 3: ['soccer', 'tennis']}
Or if you want to develop your own logic without importing any external module then you can try:
result={}
for i in zip(keys,values):
if i[0] not in result:
result[i[0]]=[i[1]]
else:
result[i[0]].append(i[1])
print(result)
output:
{1: ['apple'], 2: ['book', 'pen', 'paper'], 3: ['soccer', 'tennis']}
Related
The problem that I have is hard to explain, easy to understand:
I have a list of tuples:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
from this list I want to createa dictionary where the keys are the first elements of the tuples ('a' and 'b') and the values associated are in a list:
expected output:
{'a':['111','333'],'b':['222','444']}
How can I solve this problem?
d={}
for x in range (len(L)):
d[L[x][0]]=[L[x][1]]
return d
but as you can easy understand, the output won't be complete since the list will show just the last value associated to that key in L
You can use setdefault() to set the key in the dict the first time. Then append your value:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
d = {}
for key, value in L:
d.setdefault(key, []).append(value)
print(d)
# {'a': ['111', '333'], 'b': ['222', '444']}
You have to append L[x][1] to an existing list, not replace whatever was there with a new singleton list.
d={}
for x in range (len(L)):
if L[x][0] not in d:
d[L[x][0]] = []
d[L[x][0]].append(L[x][1])
return d
A defaultdict makes this easier:
from collections import defaultdict
d = defaultdict(list)
for x in range(len(L)):
d[L[x][0]].append(L[x][1])
return d
A more idiomatic style of writing this would be to iterate directly over the list and unpack the key and value immediately:
d = defaultdict(list)
for key, value in L:
d[key].append(value)
You can try this:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = {}
for item in L:
if item[0] not in my_dict:
my_dict[item[0]] = []
my_dict[item[0]].append(item[1])
print(my_dict)
Output:
python your_script.py
{'a': ['111', '333'], 'b': ['222', '444']}
As pointed by #chepner, you can use defaultdict to.
Basically, with defaultdict you'll not need to check if there is no key yet in your dict.
So it would be:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = defaultdict(list)
for item in L:
my_dict[item[0]].append(item[1])
print(my_dict)
And the output:
defaultdict(<class 'list'>, {'a': ['111', '333'], 'b': ['222', '444']})
And if you want to get a dict from the defaultdict, you can simply create a new dict from it:
print(dict(my_dict))
And the output will be:
{'a': ['111', '333'], 'b': ['222', '444']}
I want to take this input:
mycounter = [{6: ['Credit card']}, {2: ['Debit card']}, {2: ['Check']}]
#[{6: ['Credit card']}, {2: ['Debit card']}, {2: ['Check']}]
And achieve this Desired Output:
[{6: ['Credit card']}, {2: ['Debit card', 'Check']}]
My attempt was the following, but it's not matching desired output. Any help here is appreciated. Thx.
temp = list(zip([*map(lambda d: next(iter(d.keys())), mycounter)], [*map(lambda d: next(iter(d.values())), mycounter)]))
c = collections.defaultdict(list)
for a,b in temp:
c[a].extend(b)
final = [dict(c)]
# Close, but not quite the desired output since it's should be two dict objects, not one
# [{6: ['Credit card'], 2: ['Debit card', 'Check']}]
My searches on stackoverflow found solutions that combine with giving None values, but nothing like what i'm asking for. My question has a different input than another similar question earlier.
For the sake of giving options, here is an alternate version that uses defaultdict, which I find easier to use especially as complexity increases:
from collections import defaultdict
result = defaultdict(list)
for d in mycounter:
for k, v in d.items():
result[k] += v
In : result
Out: defaultdict(list, {6: ['Credit card'], 2: ['Debit card', 'Check']})
Defaultdict behaves like dict for the most part but if necessary it can be converted to one with:
In : dict(result)
Out: {6: ['Credit card'], 2: ['Debit card', 'Check']}
One option would be to make a single dictionary then break it into single key-value pairs after:
mycounter = [{6: ['Credit card']}, {2: ['Debit card']}, {2: ['Check']}]
res = {}
for d in mycounter:
for k, v in d.items():
res.setdefault(k, []).extend(v)
[{k:v} for k, v in res.items()]
# [{6: ['Credit card']}, {2: ['Debit card', 'Check']}]
This is very similar to another question; the only difference is that you want each key/value pair in its own dictionary. Here's an adapted solution using comprehensions and itertools:
from itertools import chain
def merge_dicts(*dicts):
return [
{ k: list(chain.from_iterable( d[k] for d in dicts if k in d )) }
for k in set(chain.from_iterable(dicts))
]
This question already has answers here:
Grouping Python dictionary keys as a list and create a new dictionary with this list as a value
(2 answers)
Closed 4 years ago.
I have a list of dictionaries. How can i group that list by valaues.
list = [{a:1},{b:2},{c:1},{d:3},{e:2}]
Now my result should be like below
1:a,c
2:b,e
3:d
I tried using groupby from itertools. But i couldn't get the required result. I am using python 2.7.
Could you help me achieve this?
If you want to use groupby, the list has to be sorted by the same key you want to group by.
>>> lst = [{'a':1}, {'b':2}, {'c':1}, {'d':3}, {'e':2}]
>>> keyfunc = lambda d: next(iter(d.values()))
>>> sorted(lst, key=keyfunc)
[{'a': 1}, {'c': 1}, {'b': 2}, {'e': 2}, {'d': 3}]
>>> {k: [x for d in g for x in d]
... for k, g in itertools.groupby(sorted(lst, key=keyfunc), key=keyfunc)}
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Here's a possible solution without using any library.
def get_dict(list):
res = {}
for elem in list:
k, v = elem.keys(), elem.values()
if v[0] in res:
res[v[0]].append(k[0])
else:
res[v[0]] = [k[0]]
return res
With a list like yours, this would output a dictionary with the following format:
{ 1:[a,c], 2:[b, e], 3:[c] }
This is considering you're always going to have the same format as input. If not, you could just adjust what is read and saved.
This might help.
list = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
d = {}
for i in list:
key, value = i.items()[0]
if value not in d:
d[value] = [key]
else:
d[value].append(key)
print(d)
Output:
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Tested in python2.7
Here is a way to do what you are looking for:
list_ = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
values = set(value for dic in list_ for value in dic.values())
for value in values:
keys = [list(dic.keys())[0] for dic in list_ if value in dic.values()]
print("{}: {}".format(value, keys))
Output:
1: ['a', 'c']
2: ['b', 'e']
3: ['d']
Here's a solution that uses defaultdict.
from __future__ import print_function
from collections import defaultdict
lst = [{'a': 1}, {'b': 2}, {'c': 1}, {'d': 3}, {'e': 2}]
d = defaultdict(list)
for l in lst:
val, key = l.items()[0]
d[key].append(val)
print(d)
Output:
defaultdict(<type 'list'>, {1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']})
I'm sure this can be done, but I have thus far been unsuccessful:
I have a list of strings. I want to create a dictionary with the length of said strings (which can be expressed as a range) as the key and the string itself as the value.
example:
Here's something like the list I have: ['foo','bar','help','this','guy']
I'd like to end up with a dictionary like this:
{3:['foo','bar','guy], 4:['this','help']}
Using defaultdict so you don't have to check whether or not to create the list for a new key:
from collections import defaultdict
x = ['foo','bar','help','this','guy']
len_dict = defaultdict(list)
for word in x:
len_dict[len(word)].append(word)
len_dict
#
# Out[5]: defaultdict(list, {3: ['foo', 'bar', 'guy'], 4: ['help', 'this']})
You can use a dictionary as a container with setdefault:
lst = ['foo','bar','help','this','guy']
result = {}
for w in lst:
result.setdefault(len(w), []).append(w)
result
# {3: ['foo', 'bar', 'guy'], 4: ['help', 'this']}
You can do it like that:
d={}
lst=['foo','bar','help','this','guy']
for i in lst:
if len(i) in d:
d[len(i)].append(i)
else:
d[len(i)]=[i]
This solution is pythonic, elegant and fast: (by the Famous Raymond Hettinger in one of his many conferences).
dict.setdefault is the dictionary method that initialises a key-value if the key is not found in dict as well as performing dict.get for provided key.
l = ['foo','bar','help','this','guy']
d = {}
for e in l:
key = len(e)
d.setdefault(key, []).append(name)
print(d)
Output:
{3: ['foo', 'bar', 'guy'], 4: ['help', 'this']}
This solution is the modern way of the solution above:
defaultdict from collection is a subclass of dict that automatically initialises value to any given key that is not in the defaultdict.
from collections import defaultdict
l = ['foo','bar','help','this','guy']
d = defaultdict(list)
for e in l:
key = len(e)
d[key].append(e)
print(d)
Output:
defaultdict(<class 'list'>, {3: ['foo', 'bar', 'guy'], 4: ['help', 'this']})
Similar to what have been said, but using the get method of dict class:
the_list=['foo','bar','help','this','guy']
d = {}
for word in the_list:
key = len(word)
d[key] = d.get(key, []) + [word]
print(d)
# {3: ['foo', 'bar', 'guy'], 4: ['help', 'this']}
Another approach:
from collections import defaultdict
given_list=['foo','bar','help','this','guy']
len_words=[len(i) for i in given_list]
d=defaultdict(list)
for i,j in list(zip(len_words,given_list)):
d[i].append(j)
I have a dictionary like this:
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
and want the inverse like this:
dict2 = dict({1:['a','b','c'], 2:['a','b','c'], 3:['a','b'], 4:['b']})
Like these questions:
Inverse Dict in Python \\
In-place dictionary inversion in Python
But I want to do it with non-unique keys and I don't want in-place conversion. I have some code working, but I was wondering if there's a dictionary comprehension way of doing this.
from collections import defaultdict
dict2 = defaultdict(list)
for i in dict1:
for j in dict1[i]:
dict2[j].append(i)
I tried this, but it only works for unique mappings. By unique I mean something like "for each value, there is only one key under which the value is listed". So unique mapping: '1: [a], 2: [b], 3: [c] -> a: [1], b: [2], c: [3]' VS non-unique mapping '1: [a], 2: [a, b], 3: [b, c] -> a: [1, 2], b: [2, 3], c: [3]'
dict2 = {j: i for i in dict1 for j in dict1[i]}
I think it must be something like this:
dict2 = {j: [i for i in dict1 if j in dict1[i]] for j in dict1[i]} # I know this doesn't work
Besides it not working, it seems like a comprehension like this would be inefficient. Is there an efficient, one liner way of doing this?
Standard dict:
>>> dict2 = {}
>>> for key, values in dict1.items():
... for value in values:
... dict2.setdefault(value, []).append(key)
...
>>> dict2
{1: ['a', 'c', 'b'], 2: ['a', 'c', 'b'], 3: ['a', 'b'], 4: ['b']}
defaultdict:
>>> dict2 = defaultdict(list)
>>> for key, values in dict1.items():
... for value in values:
... dict2[value].append(key)
...
>>> dict2
{1: ['a', 'c', 'b'], 2: ['a', 'c', 'b'], 3: ['a', 'b'], 4: ['b']}
I figured out an answer based on Vroomfondel's answer:
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = {item: [key for key in dict1 if item in dict1[key]] for value in dict1.values() for item in value}
This isn't the fastest, but it is a one liner and it is not the slowest of the options presented!
from timeit import timeit
methods = [['Vroomfondel1', '''from collections import defaultdict
import itertools
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for k,v in itertools.chain.from_iterable([itertools.product(vals,key) for key,vals in dict1.items()]):
dict2[k].append(v)'''],
['Vroomfondel2', '''from collections import defaultdict
import itertools
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
[dict2[k].append(v) for k,v in itertools.chain.from_iterable([itertools.product(vals,key) for key,vals in dict1.items()])]'''],
['***Vroomfondel2 mod', '''dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = {item: [key for key in dict1 if item in dict1[key]] for value in dict1.values() for item in value}'''],
['mhlester1', '''dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = {}
for key, values in dict1.items():
for value in values:
dict2.setdefault(value, []).append(key)'''],
['mhlester1 mod', '''from collections import defaultdict
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for key, values in dict1.items():
for value in values:
dict2[value].append(key)'''],
['mhlester2', '''from collections import defaultdict
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for key, values in dict1.items():
for value in values:
dict2[value].append(key)'''],
['initial', '''from collections import defaultdict
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for i in dict1:
for j in dict1[i]:
dict2[j].append(i)''']
]
for method in methods:
print "% 15s" % (method[0]), '\t', timeit(method[1], number=10000)
prints out:
Vroomfondel1 0.202519893646
Vroomfondel2 0.164724111557
***Vroomfondel2 mod 0.114083051682
mhlester1 0.0599339008331
mhlester1 mod 0.091933965683
mhlester2 0.0900268554688
initial 0.0953099727631
As a one-liner (thanks to mhlesters input), but with so-so readability (and only working because the values in dict2 are mutable and thus setdefault returning a reference to them):
import itertools
[dict2.setdefault(k,[]).append(v) for k,v in itertools.chain.from_iterable([itertools.product(vals,[key]) for key,vals in dict1.items()])]
Or with a for loop:
import collections
import itertools
dict2=collections.defaultdict(list)
for k,v in itertools.chain.from_iterable([itertools.product(vals,[key]) for key,vals in dict1.items()]):
dict2[k].append(v)