Divide list to multiple lists based on elements value - python

I have the following list:
initial_list = [['B', 'D', 'A', 'C', 'E']]
On each element of the list I apply a function and put the results in a dictionary:
for state in initial_list:
next_dict[state] = move([state], alphabet)
This gives the following result:
next_dict = {'D': ['E'], 'B': ['D'], 'A': ['C'], 'C': ['C'], 'E': ['D']}
What I would like to do is separate the keys from initial_list based on their
values in the next_dict dictionary, basically group the elements of the first list to elements with the same value in the next_dict:
new_list = [['A', 'C'], ['B', 'E'], ['D']]
'A' and 'C' will stay in the same group because they have the same value 'C', 'B' and 'D' will also share the same group because their value is 'D' and then 'D' will be in it's own group.
How can I achieve this result?

You need groupby, after having sorted your list by next_dict values :
It generates a break or new group every time the value of the key
function changes (which is why it is usually necessary to have sorted
the data using the same key function).
from itertools import groupby
initial_list = ['B', 'D', 'A', 'C', 'E']
def move(letter):
return {'A': 'C', 'C': 'C', 'D': 'E', 'E': 'D', 'B': 'D'}.get(letter)
sorted_list = sorted(initial_list, key=move)
print [list(v) for k,v in groupby(sorted_list, key=move)]
#=> [['A', 'C'], ['B', 'E'], ['D']]

Simplest way to achieve this will be to use itertools.groupby with key as dict.get as:
>>> from itertools import groupby
>>> next_dict = {'D': ['E'], 'B': ['D'], 'A': ['C'], 'C': ['C'], 'E': ['D']}
>>> initial_list = ['B', 'D', 'A', 'C', 'E']
>>> [list(i) for _, i in groupby(sorted(initial_list, key=next_dict.get), next_dict.get)]
[['A', 'C'], ['B', 'E'], ['D']]

I'm not exactly sure that's what you want but you can group the values based on their values in the next_dict:
>>> next_dict = {'D': 'E', 'B': 'D', 'A': 'C', 'C': 'C', 'E': 'D'}
>>> # external library but one can also use a defaultdict.
>>> from iteration_utilities import groupedby
>>> groupings = groupedby(['B', 'D', 'A', 'C', 'E'], key=next_dict.__getitem__)
>>> groupings
{'C': ['A', 'C'], 'D': ['B', 'E'], 'E': ['D']}
and then convert that to a list of their values:
>>> list(groupings.values())
[['A', 'C'], ['D'], ['B', 'E']]
Combine everything into a one-liner (not really recommended but a lot of people prefer that):
>>> list(groupedby(['B', 'D', 'A', 'C', 'E'], key=next_dict.__getitem__).values())
[['A', 'C'], ['D'], ['B', 'E']]

Try this:
next_next_dict = {}
for key in next_dict:
if next_dict[key][0] in next_next_dict:
next_next_dict[next_dict[key][0]] += key
else:
next_next_dict[next_dict[key][0]] = [key]
new_list = next_next_dict.values()
Or this:
new_list = []
for value in next_dict.values():
new_value = [key for key in next_dict.keys() if next_dict[key] == value]
if new_value not in new_list:
new_list.append(new_value)

We can sort your list with your dictionary mapping, and then use itertools.groupby to form the groups. The only amendment I made here is making your initial list an actual flat list.
>>> from itertools import groupby
>>> initial_list = ['B', 'D', 'A', 'C', 'E']
>>> next_dict = {'D': ['E'], 'B': ['D'], 'A': ['C'], 'C': ['C'], 'E': ['D']}
>>> s_key = lambda x: next_dict[x]
>>> [list(v) for k, v in groupby(sorted(initial_list, key=s_key), key=s_key)]
[['A', 'C'], ['B', 'E'], ['D']]

Related

Replace elements in list based on a dictionary mapping table

I want to replace the elements in a list of lists based on a dictionary mapping table, and tried below:
lists_before = [['A', 'B', 'C'], ['A', 'D'], ['D', 'E']]
mapped_dictionary = {'A': 'G', 'B': 'G', 'C':'F'}
Below is the code I use:
lists_after = []
for element in lists_before:
new_element = []
for letter in element :
if letter in list(mapped_dictionary.values()):
letter = repl_dic.get(letter)
new_element.append(letter)
lists_after.append(new_element)
The output expected for lists_after is:
[['G', 'G', 'F'],['G','D'],['D','E']]
However, the output I got is still the same as lists_before.
I cannot figure out what went wrong. Could someone help me?
You can do it like this:
Input:
l = [['A', 'B', 'C'], ['A', 'D'], ['D', 'E']]
m = {'A': 'G', 'B': 'G', 'C': 'F'}
Code:
l_new = list()
for lst in l:
lst_new = list()
for ele in lst:
lst_new.append(m.get(ele, ele))
l_new.append(lst_new)
Output:
[['G', 'G', 'F'], ['G', 'D'], ['D', 'E']]
Or use a 1-liner:
[[m.get(ele, ele) for ele in lst] for lst in l]
[['G', 'G', 'F'], ['G', 'D'], ['D', 'E']]

Want to change an element of a list to a dictionary key in python

I want to change a list to a dictionary and also want to make the first element of the list as key of dictionary and other elements will be the result of this key in dictionary. Thanks in advance.
This what I have :
lst = ['a', 'b', 'c', 'd']
print (list)
['a', 'b', 'c', 'd']
and this is what I desir:
dic = {'a':['b', 'c', 'd']}
print(dic)
{'a': ['b', 'c', 'd']}
or
print (dic['a'])
['b', 'c', 'd']
you can try:
lst = ['a', 'b', 'c', 'd']
dct = {lst[0]:lst[1:]}
It will give you the desired result
I thought of a function in case you need to do do this for several lists.
def todict (lst):
first, *rest = lst
return {first: rest}
In[1]: todict(lst)
Out[1]: {'a': ['b', 'c', 'd']}

How to combine every 5 lists inside of a list in python?

I have a large list of lists, for example:
list = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
I would like to combine every 5 lists into one list of elements and so on.
I am having total of 150995 lists inside a list.
Expected output:
new_list = [['a' , 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
I tried with below code. but it is flattens to one list.
list(zip(*list)[0])
How can I do this?
you basically want to group evenly sized chunks of lists. It's possible using itertools.chain and slicing with range and a step of 5
import itertools
lst = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
result = [list(itertools.chain.from_iterable(itertools.islice(lst,i,i+5))) for i in range(0,len(lst),5)]
print(result)
result:
[['a', 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
notes:
using itertools.islice avoids a standard lst[i:i+5] slicing that creates a useless list object
it works even when the number of elements isn't divisible by 5.
Given:
>>> li = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
You can do:
>>> list(map(list, zip(*[iter([e for sublist in li for e in sublist])]*5)))
[['a', 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
Or,
>>> [[e for sublist in lst[i:i+5] for e in sublist] for i in range(0,len(lst),5)]
[['a', 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
This solution is convenient since it uses nothing besides numpy
If your list always has elements divisible by 5, then
import numpy as np
oldlist = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
newlist = np.reshape(oldlist,(len(oldlist)//5,5)).T.tolist()
newlist will have your desired output of
[['a' , 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
Use itertools.chain to flatten the list and itertools.zip_longest to group the elemensts in chunks of 5
>>> from itertools import zip_longest, chain
>>> n = 5
>>> list(zip_longest(*[chain(*List)]*n))
[('a', 'b', 'c', '1234', 'd'), ('e', 'g', 'h', 'i', '56')]
If you are not happy with the result being list of tuples, you can convert the individual elements from tuple to list using map
>>> list(map(list, zip_longest(*[chain(*List)]*5)))
[['a', 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
Many good solutions already. I just wanted to add one more possiblity that is using a custom Iterator like so:
from itertools import chain
class MyIter:
def __init__(self, lists,n_first):
self.lists = lists
self.index = 0
self.n_first = n_first
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.lists):
temp = list(chain(*self.lists[self.index:min(self.index+self.n_first,len(self.lists))]))
self.index += self.n_first
return temp
else:
raise StopIteration
_list = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
print(list(MyIter(_list,5)))
Assuming the len(list) is a multiple of 5, the following solution works:
list = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
row = int(len(list)/5)
new_list = [i.tolist() for i in np.array(list).reshape((row,5))]
print (new_list)
resulting in
[['a', 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
Here's a non-library list comprehension solution:
>>> L = [['a'], ['b'], ['c'], ['1234'], ['d'], ['e'], ['g'], ['h'], ['i'], ['56']]
>>> [[j[0] for j in L[i:i+5]] for i in range(0, len(L), 5)]
[['a', 'b', 'c', '1234', 'd'], ['e', 'g', 'h', 'i', '56']]
By the way, calling your list list redefines a builtin function.

Merging Key-Value Pairings in Dictionary

I have a dictionary that consists of employee-manager as key-value pairs:
{'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
I want to show the relations between employee-manager at all levels (employee's boss, his boss's boss, his boss's boss's boss etc.) using a dictionary. The desired output is:
{'a': [b,d,f], 'b': [d,f], 'c': [d,f], 'd': [f] }
Here is my attempt which only shows the first level:
for key, value in data.items():
if (value in data.keys()):
data[key] = [value]
data[key].append(data[value])
I can do another conditional statement to add the next level but this would be the wrong way to go about it. I'm not very familiar with dictionaries so what would be a better approach?
>>> D = {'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
>>> res = {}
>>> for k in D:
... res[k] = [j] = [D[k]]
... while j in D:
... j = D[j]
... res[k].append(j)
...
>>> res
{'b': ['d', 'f'], 'c': ['d', 'f'], 'd': ['f'], 'a': ['b', 'd', 'f']}
You may use the concept of recursion as :
def get_linked_list(element, hierarchy, lst):
if element:
lst.append(element)
return get_linked_list(hierarchy.get(element, ""), hierarchy, lst)
else:
return lst
And then access the hierarchy as:
>>> d = {'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
>>> print {elem:get_linked_list(elem, d, [])[1:] for elem in d.keys()}
>>> {'a': ['b', 'd', 'f'], 'c': ['d', 'f'], 'b': ['d', 'f'], 'd': ['f']}
However care must be taken as this may get to an infinite loop if we have an item in the dictionary as "a": "a"
x={'a': 'b', 'b': 'd', 'c': 'd', 'd': 'f'}
d={}
l=x.keys()
for i in l:
d.setdefault(i,[])
d[i].append(x[i])
for j in l[l.index(i)+1:]:
if j==d[i][-1]:
d[i].append(x[j])
print d
Output:{'a': ['b', 'd', 'f'], 'c': ['d', 'f'], 'b': ['d', 'f'], 'd': ['f']}

python reverse/transponse a dictionary [duplicate]

This question already has answers here:
Invert keys and values of the original dictionary
(3 answers)
Closed 8 years ago.
I am looking to tranpose a dictionary on python and after looking around i was not able to ifnd a solution for this. Does anybody know how could i reverse a dictionary like the following as input:
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
so that i get something like:
newgraph = {'A': [''],
'B': ['A'],
'C': ['A', 'B', 'D','F'],
'D': ['B', 'C'],
'E': [''],
'F': ['E']}
Use defaultdict:
newgraph = defaultdict(list)
for x, adj in graph.items():
for y in adj:
newgraph[y].append(x)
While it doesn't seem to make any sense to have the empty string '' in the empty lists, it's certainly possible:
for x in newgraph:
newgraph[x] = newgraph[x] or ['']
Use defaultdict:
>>> from collections import defaultdict
>>> graph = {'A': ['B', 'C'],
... 'B': ['C', 'D'],
... 'C': ['D'],
... 'D': ['C'],
... 'E': ['F'],
... 'F': ['C']}
>>> new_graph = defaultdict(list)
>>> for ele in graph.keys():
... new_graph[ele] = []
...
>>> for k, v in graph.items():
... for ele in v:
... new_graph[ele].append(k)
...
>>> pprint(new_graph)
{'A': [],
'B': ['A'],
'C': ['A', 'B', 'D', 'F'],
'D': ['B', 'C'],
'E': [],
'F': ['E']}
It's also possible without defaultdict.
Here I've left the empty keys in the new dict with the value None.
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
g = dict.fromkeys(graph.keys())
for k, v in graph.iteritems():
for x in v:
if g[x]: g[x] += [k]
else: g[x] = [k]
for k in sorted(graph.keys()):
print k, ':', g[k]
Output:
A : None
B : ['A']
C : ['A', 'B', 'D', 'F']
D : ['C', 'B']
E : None
F : ['E']

Categories

Resources