I'm looking for a way to convert a list of tuples like this:
[(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
into a dictionary like this:
{4:[1,2,3] ,15:[4,5,9,11,12], 23:[6,7,8,10]}
The second element from each tuple becomes a dictionary key, and all the first tuple elements associated with that key are stored in a value list.
Can you show me how that can be done?
>>> from collections import defaultdict
>>> l= [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
>>> d= defaultdict( list )
>>> for v, k in l:
... d[k].append(v)
...
>>> d
defaultdict(<type 'list'>, {23: [6, 7, 8, 10], 4: [1, 2, 3], 15: [4, 5, 9, 11, 12]})
>>> [ {k:d[k]} for k in sorted(d) ]
[{4: [1, 2, 3]}, {15: [4, 5, 9, 11, 12]}, {23: [6, 7, 8, 10]}]
>>> a = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
>>> b = {}
>>> for i, j in a:
... b.setdefault(j, []).append(i)
...
>>> b
{23: [6, 7, 8, 10], 4: [1, 2, 3], 15: [4, 5, 9, 11, 12]}
>>>
tuples = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
dicts = {}
for elem in tuples:
try:
dicts[elem[1]].append(elem[0])
except KeyError:
dicts[elem[1]] = [elem[0],]
l = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
d = {}
for v, k in l:
d.setdefault(k, []).append(v)
This will do:
from collections import defaultdict
def to_list_of_dicts(list_of_tuples):
d = defaultdict(list)
for x, y in list_of_tuples:
d[y].append(x)
return sorted([{x: y} for (x, y) in d.items()])
It's not fancy but it is simple
l = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
d = dict((k, [i[0] for i in l if i[1] == k]) for k in frozenset(j[1] for j in l))
Huzzah!
for key, value in tuples:
if d.get(key):
d[key].append(value)
continue
d[key] =[value]
Related
I am looking to extend the approach taken here but for the case of six or more lists: How to Create Nested Dictionary in Python with 3 lists
a = ['A', 'B', 'C', 'D']
b = [1, 2, 3, 4]
c = [9, 8, 7, 6]
d = [0, 3, 5, 7]
e = [11, 13, 14, 15]
Desired output:
{'A':{1 :9, 0:11} , 'B':{2:8, 3:13}, 'C':{3:7, 5:13} , 'D':{4:6, 7:15}}
Here's what I've tried so far:
out = dict([[a, dict([map(str, i)])] for a, i in zip(a, zip(zip(b, c), zip(d,e) ))])
The output is close, but it's not quite what I'm looking for. Any tips would be greatly appreciated!
Maybe something like:
out = {k: {k1: v1, k2: v2} for k, k1, v1, k2, v2 in zip(a, b, c, d, e)}
If we want to use excessive number of zips, we could also do:
out = {k: dict(v) for k,v in zip(a, zip(zip(b, c), zip(d, e)))}
Output:
{'A':{1 :9, 0:11} , 'B':{2:8, 3:13}, 'C':{3:7, 5:13} , 'D':{4:6, 7:15}}
Here's an approach that uses two dictionary comprehensions and zip():
result = {key: { inner_key: inner_value for inner_key, inner_value in value}
for key, value in zip(a, zip(zip(b, c), zip(d, e)))
}
print(result)
The result, using the lists in the original question:
{'A': {1: 9, 0: 11}, 'B': {2: 8, 3: 13}, 'C': {3: 7, 5: 14}, 'D': {4: 6, 7: 15}}
You could try NestedDict. First install ndicts
pip install ndicts
Then
from ndicts.ndicts import NestedDict
a = ['A', 'B', 'C', 'D']
b = [1, 2, 3, 4]
c = [9, 8, 7, 6]
d = [0, 3, 5, 7]
e = [11, 13, 14, 15]
# Create levels and values
level_0 = a * 2
level_1 = b + d
values = c + e
# Initialize the keys of a NestedDict
nd = NestedDict.from_tuples(*zip(level_0, level_1))
# Assign values
for key, value in zip(nd, values):
nd[key] = value
If you need the result as a dictionary
result = nd.to_dict()
I have a dictionary
d = {1: 3, 5: 6, 10: 2}
I want to convert it to a list that holds the keys of the dictionary. Each key should be repeated as many times as its associated value.
I've written this code that does the job:
d = {1: 3, 5: 6, 10: 2}
l = []
for i in d:
for j in range(d[i]):
l.append(i)
l.sort()
print(l)
Output:
[1, 1, 1, 5, 5, 5, 5, 5, 5, 10, 10]
But I would like it to be a list comprehension. How can this be done?
You can do it using a list comprehension:
[i for i in d for j in range(d[i])]
yields:
[1, 1, 1, 10, 10, 5, 5, 5, 5, 5, 5]
You can sort it again to get the list you were looking for.
[k for k,v in d.items() for _ in range(v)]
... I guess...
if you want it sorted you can do
[k for k,v in sorted(d.items()) for _ in range(v)]
One approach is to use itertools.chain to glue sublists together
>>> list(itertools.chain(*[[k]*v for k, v in d.items()]))
[1, 1, 1, 10, 10, 5, 5, 5, 5, 5, 5]
Or if you are dealing with a very large dictionary, then you could avoid constructing the sub lists with itertools.chain.from_iterable and itertools.repeat
>>> list(itertools.chain.from_iterable(itertools.repeat(k, v) for k, v in d.items()))
[1, 1, 1, 10, 10, 5, 5, 5, 5, 5, 5]
Comparative timings for a very large dictionary with using a list comprehension that uses two loops:
>>> d = {i: i for i in range(100)}
>>> %timeit list(itertools.chain.from_iterable(itertools.repeat(k, v) for k, v in d.items()))
10000 loops, best of 3: 55.6 µs per loop
>>> %timeit [k for k, v in d.items() for _ in range(v)]
10000 loops, best of 3: 119 µs per loop
It's not clear whether you want your output sorted (your example code does not sort it), but if so simply presort d.items()
# same as previous examples, but we sort d.items()
list(itertools.chain(*[[k]*v for k, v in sorted(d.items())]))
Counter.elements() method does exactly this:
from collections import Counter
d = {1: 3, 5: 6, 10: 2}
c = Counter(d)
result = list(c.elements())
print(result)
# [1, 1, 1, 5, 5, 5, 5, 5, 5, 10, 10]
This is what I am doing:
Where data is a list of lists in the form of [[int1, int2, int3], [int1, int2,int3]].
I want a dictionary that looks like: {int1: [int2, int3], in2:[int2, int3]}.
I am checking what the size of data is before the dictionary comprehension and it is 1417.
I then check what the length of the dictionary is and it is something like 11, I don't know what is happening to the data list since all of the elements are not being copied into containsBacon.
def makeComprehension(data):
containsBacon = dict([(movies[2], movies[0:2]) for movies in data])
Here's a way to do it:
>>> l = [[1,2,3], [10,20,30]]
>>> d = {m[0]:m[1:] for m in l}
>>> d
{1: [2, 3], 10: [20, 30]}
Note that not all the elements will be in the resulting dictionary, because if two lists start with the same elements, this will create the same key, and will therefore not appear.
If you want to have all your original elements in your resulting dictionary, you can do the following:
>>> l = [[1,2,3], [10,20,30], [1,5,6]
>>> {m[0]:[x for n in l if n[0]==m[0] for x in n[1:]] for m in l}
{1: [2, 3, 5, 6], 10: [20, 30]}
Similar to #DevShark answer, but with destructuring assignment:
>>> L = [[1,2,3], [10,20,30], [1,5,6]]
>>> {k:v for k,*v in L}
{1: [5, 6], 10: [20, 30]}
If you want to concatenate the values for a given key, do not use a dict comprehension:
>>> d = {}
>>> for k,*v in L: d.setdefault(k, []).extend(v)
...
>>> d
{1: [2, 3, 5, 6], 10: [20, 30]}
The setdefault method creates the d[k] entry and set it to an empty list if it does not exist.
This solution is O(n) vs O(n^2) in #DevShark answer.
Here's another O(n) version:
>>> import functools
>>> functools.reduce(lambda d,m:{**d, m[0]:d.get(m[0], []) + m[1:]}, L, {})
{1: [2, 3, 5, 6], 10: [20, 30]}
d[m[0]] is updated to its previous value + m[1:]
If you want a dict comprehension, you may use itertools.groupby for a O(n lg n) solution:
>>> import itertools
>>> L.sort() # O(n lg n) part
>>> L
[[1, 2, 3], [1, 5, 6], [10, 20, 30]]
{k:[v for m in ms for v in m[1:]] for k, ms in itertools.groupby(L, lambda m:m[0])}
{1: [2, 3, 5, 6], 10: [20, 30]}
I'm looking for a way to convert a list of tuples like this:
[(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
into a dictionary like this:
{4:[1,2,3] ,15:[4,5,9,11,12], 23:[6,7,8,10]}
The second element from each tuple becomes a dictionary key, and all the first tuple elements associated with that key are stored in a value list.
Can you show me how that can be done?
>>> from collections import defaultdict
>>> l= [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
>>> d= defaultdict( list )
>>> for v, k in l:
... d[k].append(v)
...
>>> d
defaultdict(<type 'list'>, {23: [6, 7, 8, 10], 4: [1, 2, 3], 15: [4, 5, 9, 11, 12]})
>>> [ {k:d[k]} for k in sorted(d) ]
[{4: [1, 2, 3]}, {15: [4, 5, 9, 11, 12]}, {23: [6, 7, 8, 10]}]
>>> a = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
>>> b = {}
>>> for i, j in a:
... b.setdefault(j, []).append(i)
...
>>> b
{23: [6, 7, 8, 10], 4: [1, 2, 3], 15: [4, 5, 9, 11, 12]}
>>>
tuples = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
dicts = {}
for elem in tuples:
try:
dicts[elem[1]].append(elem[0])
except KeyError:
dicts[elem[1]] = [elem[0],]
l = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
d = {}
for v, k in l:
d.setdefault(k, []).append(v)
This will do:
from collections import defaultdict
def to_list_of_dicts(list_of_tuples):
d = defaultdict(list)
for x, y in list_of_tuples:
d[y].append(x)
return sorted([{x: y} for (x, y) in d.items()])
It's not fancy but it is simple
l = [(1,4),(2,4),(3,4),(4,15),(5,15),(6,23),(7,23),(8,23),(9,15),(10,23),(11,15),(12,15)]
d = dict((k, [i[0] for i in l if i[1] == k]) for k in frozenset(j[1] for j in l))
Huzzah!
for key, value in tuples:
if d.get(key):
d[key].append(value)
continue
d[key] =[value]
a = [2,2,2,3,4,5,5,6,6,6,7,7]
b = [1,2,3,4,5,6,7,8,9,10,11,12]
I want to sum the numbers in 'b' that in 'a' are the same and remove the duplicated numbers in 'a', so the output should look like:
a = [2,3,4,5,6,7]
b = [6,4,5,13,27,23]
Use a list comprehension, zipping the two lists together:
sums = [sum(y for x, y in zip(a, b) if x == i) for i in [j[0] for j in groupby(a)]]
You can use izip_longest and collections.defaultdict this is a fast and comprehensive way for solve this problem as it works if the length of a and b was not the same :
>>> from collections import defaultdict
>>> from itertools import izip_longest
>>> d=defaultdict(int)
>>> for i,j in izip_longest(a,b):
... d[i]+=j
...
>>> d
defaultdict(<type 'int'>, {2: 6, 3: 4, 4: 5, 5: 13, 6: 27, 7: 23})
>>> d.values()
[6, 4, 5, 13, 27, 23]
But as Padraic Cunningham noted dicts are not ordered although in this case the answer is true!!
as an alternative answer but less efficient you can use itertools.groupby :
>>> from itertools import izip_longest,groupby
>>> from operator import itemgetter
>>> [sum([i[1] for i in g]) for _,g in groupby(izip_longest(a,b),key=itemgetter(0))]
[6, 4, 5, 13, 27, 23]
OrderedDict.fromkeys will create a set of the elements in a and keep order:
a = [2,2,2,3,4,5,5,6,6,6,7,7]
b = [1,2,3,4,5,6,7,8,9,10,11,12]
from collections import OrderedDict
from itertools import islice
od = OrderedDict.fromkeys(a,0,)
for ele in a:
od[ele] += 1
it = iter(b)
sums = [sum(islice(it,v)) for v in od.values()]
print(list(od))
print(sums)
[2, 3, 4, 5, 6, 7]
[6, 4, 5, 13, 27, 23]
If you use a set you will have no guaranteed order, it is also unclear if you have elements that repeat later in your list a and what exactly happens if that is the case.
To work with later repeating elements:
a = [2, 2, 2, 3, 4, 5, 5, 6, 6, 7, 6, 7, 7]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13]
from collections import OrderedDict
from itertools import islice, count
it = iter(a)
seq = 1
prev = next(it)
cn = count()
od = OrderedDict()
for ele in it:
if ele == prev:
seq += 1
else:
od[next(cn)] = seq
seq = 1
prev = ele
if prev == ele:
seq += 1
od[next(cn)] = seq
st_a = OrderedDict.fromkeys(a)
it = iter(b)
sums = [sum(islice(it, v)) for v in od.values()]
print(list(st_a))
print(sums)
[0, 1, 2, 3, 4, 5, 6, 7]
[6, 4, 5, 13, 17, 10, 11, 25]