Meryem
Meryem

Reputation: 487

Divide list to multiple lists based on elements value

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?

Upvotes: 8

Views: 1518

Answers (5)

MSeifert
MSeifert

Reputation: 152637

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

Upvotes: 3

Eric Duminil
Eric Duminil

Reputation: 54223

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

Upvotes: 5

Moinuddin Quadri
Moinuddin Quadri

Reputation: 48067

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

Upvotes: 3

barak manos
barak manos

Reputation: 30136

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)

Upvotes: 2

miradulo
miradulo

Reputation: 29690

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

Upvotes: 2

Related Questions