Combine list of lists with similar values in python - python

I have a list of lists, like so:
items = [['118', 'white'], ['118','Jack'], ['118','guilty'], ['200','black'], ['200','mark'], ['200','not guilty']]
Is there a way to use a for loop to grab the second value in each list and collapse it into a new list?
Like so:
['white', 'jack', 'guilty']
['black','mark','not guilty']

Assuming your list always has elements with the same key grouped as in your example, you can use itertools.groupby() to do this efficiently:
>>> import itertools
>>> items = [['118', 'white'], ['118','Jack'], ['118','guilty'], ['200','black'], ['200','mark'], ['200','not guilty']]
>>> [[x[1] for x in g] for k, g in itertools.groupby(items, lambda x: x[0])]
[['white', 'Jack', 'guilty'], ['black', 'mark', 'not guilty']]
You could also use operator.itemgetter(0) as an alternative to lambda x: x[0].
Note that if items does not necessarily have elements grouped by their keys, you can use sorted(items) instead of items in the groupby() call and it will work.
Here is a version that preserves the key as well:
>>> [(k, [x[1] for x in g]) for k, g in itertools.groupby(items, lambda x: x[0])]
[('118', ['white', 'Jack', 'guilty']), ('200', ['black', 'mark', 'not guilty'])]
You could pass this list directly into the dict() built-in function to convert this to a dictionary.

from collections import defaultdict
entries = defaultdict(list)
for (key, value) in items:
entries[key].append(value)
Now entries is a dict of lists of the second values. You can either get them by key ('118') or use values() for a list of lists.

>>> k = set(x[0] for x in items)
>>> [ [x[1] for x in items if x[0] == key] for key in sorted(k) ]
[['white', 'Jack', 'guilty'], ['black', 'mark', 'not guilty']]

output_dict = {}
for each_key in items:
for each_item in each_key:
try:
output_dict[each_key].append(each_item) #fails as I'm trying to use a list as a dict key
except Exception as e:
output_dict[each_key] = [] #see above
output_dict[each_key].append(each_item) #see above
for each_list in output_dict:
print(each_list)
as Peter DeGlopper pointed out below, this code is bad and I should feel bad. I've commented the code to point out my error. There are better solutions, but just to correct my mistake:
items = [['118', 'white'], ['118','Jack'], ['118','guilty'], ['200','black'], ['200','mark'], ['200','not guilty']]
output_dict = {}
for each_list in items:
if each_list[0] not in output_dict: output_dict[each_list[0]] = list()
output_dict[each_list[0]].append(each_list[1])
>>> for each_list in output_dict:
>>> print(each_list)
['white','Jack','guilty']
['black','mark','not guilty']

Related

Sperate the list based on a value in python

I have a list like below:-
list1 = ['box','ball','new','bat','chess','old']
I want to split this list based on values. In the above list, I want to insert the values before 'new' into a new list and the values before 'old' have to be inserted into a new list. The values before 'new' and 'old' can be one or more but here it has two values. I tried using split_after but I am getting the below result:-
from more_itertools import split_after
list1 = ['box','ball','new','bat','chess','old']
list(split_after(list1, lambda x: x == "new"))
Result:-
[['box', 'ball', 'new'], ['bat', 'chess', 'old']]
But desire output:-
result1 = ['box', 'ball']
result2 = ['bat', 'chess']
You might use split_at, and in the lambda check for either new or old.
Then remove the empty lists from the result.
from more_itertools import split_at
list1 = ['box', 'ball', 'new', 'bat', 'chess', 'old']
print(list(filter(None, split_at(list1, lambda x: x == "new" or x == "old"))))
Output
[['box', 'ball'], ['bat', 'chess']]
Another solution, using standard itertools.groupby:
list1 = ["box", "ball", "new", "bat", "chess", "old"]
from itertools import groupby
out = [
list(g) for v, g in groupby(list1, lambda k: k in {"new", "old"}) if not v
]
print(out)
Prints:
[['box', 'ball'], ['bat', 'chess']]
If the values are more based on which you have to split like new and old, you can do this:
list1 = ['box','ball','new','bat','chess','old']
split_val = ['new','old'] # Based on these values you can separate list. You can add more values here.
new_list=[]
k=0
for i in split_val:
for j in range(len(list1)):
if list1[j]==i and j!=0:
new_list.append(list1[k:j])
k=j+1
new_list.append(list1[k:])
new_list = [i for i in new_list if len(i)>0]
print(new_list)
Output:
[['box', 'ball'], ['bat', 'chess']]

Python: Create a dictionary where keys have multiple values

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

Python: Split a list into smaller jsons based on another list

I have one list of program names which need to be sorted into lists of smaller jsons based of a priority list. I need to do this in python 3.
B and C being of the same priority 2, they will be in a list together.
program_names = ['A','B','C','D']
priorities = [1,2,2,3]
Required end result:
[[{"name": "A"}], [{"name":"B"}, {"name":"C"}], [{"name":"D"}]]
Current code:
program_names_list = []
final_list = []
for x in program_names.split(','):
program_names_list.append(x)
for x in program_names_list:
final_list.append([{"name": x}])
That's what I currently have which is outputting the following result:
[[{'name': 'A'}], [{'name': 'B'}], [{'name': 'C'}], [{'name': 'D'}]]
I should add that program_names is a string "A,B,C,D"
Full solution
items = {}
for k, v in zip(priorities, program_names):
items.setdefault(k, []).append(v)
[[{'name': name} for name in items[key]] for key in sorted(items.keys())]
returns:
[[{'name': 'A'}], [{'name': 'B'}, {'name': 'C'}], [{'name': 'D'}]]
In steps
Create a dictionary that uses the priorities as keys and a list of all program names with corresponding priority as values:
items = {}
for k, v in zip(priorities, program_names):
items.setdefault(k, []).append(v)
Go through the sorted keys and create a new list of program names by getting them from the dictionary by the key:
[[{'name': name} for name in items[key]] for key in sorted(items.keys())]
Loop through the priorities and use a dictionary with priorities as keys and lists of programs as values to group all elements with the same priority.
In [24]: from collections import defaultdict
In [25]: program_names = ['A','B','C','D']
In [26]: priorities = [1,2,2,3]
In [27]: d = defaultdict(list)
In [28]: for i, p in enumerate(sorted(priorities)):
d[p].append({'name': program_names[i]})
....:
In [29]: list(d.values())
Out[29]: [[{'name': 'A'}], [{'name': 'B'}, {'name': 'C'}], [{'name': 'D'}]]
Use groupby.
from itertools import groupby
program_names = ['a','b','c','d']
priorities = [1,2,2,3]
data = zip(priorities, program_names)
groups_dict = []
for k, g in groupby(data, lambda x: x[0]):
m = map(lambda x: dict(name=x[1]), list(g))
groups_dict.append(m)
print(groups_dict)
Although this may be wrong from an educational point of view, I cannot resist answering such questions by one-liners:
[[{'name': p_n} for p_i, p_n in zip(priorities, program_names) if p_i == p] for p in sorted(set(priorities))]
(This assumes your "priorities" list may be sorted and is less efficient than the "normal" approach with a defaultdict(list)).
Update: Borrowing from damn_c-s answer, here's an efficient one-liner (not counting the implied from itertools import groupby):
[[{'name': pn} for pi, pn in l] for v, l in groupby(zip(priorities, program_names), lambda x: x[0])]

split dictionary into two lists , one list is for key, another list is for value

I want to split dictionary into two lists. one list is for key, another list is for value.
And it should be ordered as original
Original list:
[{"car":45845},{"house": 123}]
Expected result:
list1 = ["car", "house"]
list2 = [45845, 123]
fixed_list = [x.items() for x in list]
keys,values = zip(*fixed_list)
list1 = [k for item in [{"car":45845},{"house": 123}] for k,v in item.iteritems()]
list2 = [v for item in [{"car":45845},{"house": 123}] for k,v in item.iteritems()]
For Python 3 use dict.items() instead of dict.iteritems()
original = [{"car":45845},{"house": 123}]
a_dict = {}
for o in original:
a_dict.update(o)
print a_dict
print a_dict.keys()
print a_dict.values()
Output:
{'car': 45845, 'house': 123}
['car', 'house']
[45845, 123]
a =[{"car":45845},{"house": 123}]
list1 = [i.values()[0] for i in a] #iterate over values
list2= [i.keys()[0] for i in a] #iterate over keys

How can I use python itertools.groupby() to group a list of strings by their first character?

I have a list of strings similar to this list:
tags = ('apples', 'apricots', 'oranges', 'pears', 'peaches')
How should I go about grouping this list by the first character in each string using itertools.groupby()? How should I supply the 'key' argument required by itertools.groupby()?
You might want to create dict afterwards:
from itertools import groupby
d = {k: list(v) for k, v in groupby(sorted(tags), key=lambda x: x[0])}
groupby(sorted(tags), key=operator.itemgetter(0))
>>> for i, j in itertools.groupby(tags, key=lambda x: x[0]):
print(i, list(j))
a ['apples', 'apricots']
o ['oranges']
p ['pears', 'peaches']
just another way,
>>> from collections import defaultdict
>>> t=defaultdict(list)
>>> for items in tags:
... t[items[0]].append(items)
...
>>> t
defaultdict(<type 'list'>, {'a': ['apples', 'apricots'], 'p': ['pears', 'peaches'], 'o': ['oranges']})

Categories