How to make dictionary from list of lists - python

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]}

Related

Slice list based on values in another list

I have long lists, for example:
list1 = ["a","a","b","b","c"]
list2 = [1, 3, 5, 7, 9]`
How can I slice the second list based on the first list (list1 is sorted by its values)?
Like [[1,3],[5,7],[9]]
My lists are very long so I am looking for a fast way to precess this. Thanks!
With itertools.groupby() and a bit of effort.
>>> [[b[1] for b in r] for p,r in itertools.groupby(zip(list1, list2), operator.itemgetter(0))]
[[1, 3], [5, 7], [9]]
Use itertools.izip() instead of zip() if you're running 2.x.
You could also just use a dictionary:
from collections import defaultdict
list1 = ["a","a","b","b","c"]
list2 = [1, 3, 5, 7, 9]
d = defaultdict(list)
for k, v in zip(list1, list2):
d[k].append(v)
>>> print([lst for lst in sorted(d.values())])
[[1, 3], [5, 7], [9]]

Python: Nested list with similar values to dictionnary [duplicate]

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]

Divide tuple into multiple sub-tuples - Python

Not sure how to express this spefically in the title. But let's say I have this tuple:
[['a',2,3],['a',4,5],['b',10,20],['b',30,40],['a',5,6]]
How do I divide this tuple into two tuples:
a = [[2,3],[4,5],[5,6]]
b = [[10,20],[30,40]]
Assuming 'a' and 'b' are meaningful constants that deserve to be hard-coded, a simple solution:
arr = [['a',2,3],['a',4,5],['b',10,20],['b',30,40],['a',5,6]]
a = [l[1:] for l in arr if l[0] == 'a']
b = [l[1:] for l in arr if l[0] == 'b']
If a more generic code is needed:
from collections import defaultdict
arr = [['a',2,3],['a',4,5],['b',10,20],['b',30,40],['a',5,6]]
d = defaultdict(list)
for l in arr:
d[l[0]].append(l[1:])
You can do that using list comprehension:
>>> l = [['a',2,3],['a',4,5],['b',10,20],['b',30,40],['a',5,6]]
>>> a = [x[1:] for x in l if x[0] == "a"]
>>> a
[[2, 3], [4, 5], [5, 6]]
>>> b = [x[1:] for x in l if x[0] == "b"]
>>> b
[[10, 20], [30, 40]]
>>>
You need to iterate over the elements (sublists) in the main list. For each sublist, we check if the first item. If the first item is a or b, we then slice the sub list and only take the integer parts.
As jonrsharpe suggests, it's probably more useful to store those lists in a dictionary. It's easy to divide the sublists in the way you want using a dictionary to accumulate the sublists into lists as the values with the strings as the keys. And of course you can bind the resulting lists to separate names if you really want to.
seq = [['a', 2, 3], ['a', 4, 5], ['b', 10, 20], ['b', 30, 40], ['a', 5, 6]]
d = {}
for k, *u in seq:
d.setdefault(k, []).append(u)
print(d)
a = d['a']
b = d['b']
print(a)
print(b)
output
{'a': [[2, 3], [4, 5], [5, 6]], 'b': [[10, 20], [30, 40]]}
[[2, 3], [4, 5], [5, 6]]
[[10, 20], [30, 40]]
for k, *u in seq: binds the string in each sublist to k, storing the remainder of the sublist as u. We then append the u sublist to the appropriate list in the dictionary d.

Mapping two list without looping

I have two lists of equal length. The first list l1 contains data.
l1 = [2, 3, 5, 7, 8, 10, ... , 23]
The second list l2 contains the category the data in l1 belongs to:
l2 = [1, 1, 2, 1, 3, 4, ... , 3]
How can I partition the first list based on the positions defined by numbers such as 1, 2, 3, 4 in the second list, using a list comprehension or lambda function. For example, 2, 3, 7 from the first list belongs to the same partition as they have corresponding values in the second list.
The number of partitions is known at the beginning.
You can use a dictionary:
>>> l1 = [2, 3, 5, 7, 8, 10, 23]
>>> l2 = [1, 1, 2, 1, 3, 4, 3]
>>> d = {}
>>> for i, j in zip(l1, l2):
... d.setdefault(j, []).append(i)
...
>>>
>>> d
{1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]}
If a dict is fine, I suggest using a defaultdict:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for number, category in zip(l1, l2):
... d[category].append(number)
...
>>> d
defaultdict(<type 'list'>, {1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]})
Consider using itertools.izip for memory efficiency if you are using Python 2.
This is basically the same solution as Kasramvd's, but I think the defaultdict makes it a little easier to read.
This will give a list of partitions using list comprehension :
>>> l1 = [2, 3, 5, 7, 8, 10, 23]
>>> l2 = [1, 1, 2, 1, 3, 4, 3]
>>> [[value for i, value in enumerate(l1) if j == l2[i]] for j in set(l2)]
[[2, 3, 7], [5], [8, 23], [10]]
A nested list comprehension :
[ [ l1[j] for j in range(len(l1)) if l2[j] == i ] for i in range(1, max(l2)+1 )]
If it is reasonable to have your data stored in numpy's ndarrays you can use extended indexing
{i:l1[l2==i] for i in set(l2)}
to construct a dictionary of ndarrays indexed by category code.
There is an overhead associated with l2==i (i.e., building a new Boolean array for each category) that grows with the number of categories, so that you may want to check which alternative, either numpy or defaultdict, is faster with your data.
I tested with n=200000, nc=20 and numpy was faster than defaultdict + izip (124 vs 165 ms) but with nc=10000 numpy was (much) slower (11300 vs 251 ms)
Using some itertools and operator goodies and a sort you can do this in a one liner:
>>> l1 = [2, 3, 5, 7, 8, 10, 23]
>>> l2 = [1, 1, 2, 1, 3, 4, 3]
>>> itertools.groupby(sorted(zip(l2, l1)), operator.itemgetter(0))
The result of this is a itertools.groupby object that can be iterated over:
>>> for g, li in itertools.groupby(sorted(zip(l2, l1)), operator.itemgetter(0)):
>>> print(g, list(map(operator.itemgetter(1), li)))
1 [2, 3, 7]
2 [5]
3 [8, 23]
4 [10]
This is not a list comprehension but a dictionary comprehension. It resembles #cromod's solution but preserves the "categories" from l2:
{k:[val for i, val in enumerate(l1) if k == l2[i]] for k in set(l2)}
Output:
>>> l1
[2, 3, 5, 7, 8, 10, 23]
>>> l2
[1, 1, 2, 1, 3, 4, 3]
>>> {k:[val for i, val in enumerate(l1) if k == l2[i]] for k in set(l2)}
{1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]}
>>>

Pythonic way to convert list of tuples to dict of lists? [duplicate]

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]

Categories

Resources