How do I split a list into a list of smaller lists based on a predicate?

Let's say I have a list like this:

[('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]

      

And I would like to convert it to a list like this:

[ [('Yadda', 5), ('Yadda', 9)], [('Blah', 12), ('Blah', 2), ('Blah', 4)] ]

      

Assuming the list is sorted by the predicate on which it should be split -

What's the pythonic way to do this?

Is there any function that does this or do I need to write it myself?

+3


source to share


5 answers


You can use itertools.groupby

.



from itertools import groupby

l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]

l.sort(key=lambda item: item[0])

result = [list(group) for _, group in groupby(l, key=lambda item: item[0])]

      

+8


source


The itertools grouping groups adjacent elements.

>>> from itertools import groupby
>>> l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> print [list(group) for _, group in groupby(l, key=lambda item: item[0])]
[[('Yadda', 5), ('Yadda', 9)], [('Blah', 12), ('Blah', 2), ('Blah', 4)]]
>>>
>>> #if the list is not sorted!     
>>> l2 = [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)]
>>> print [list(group) for _, group in groupby(l2, key=lambda item: item[0])]
[[('Yadda', 9)], [('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5)]]

      

  • Its important to sort the list before proceeding!

So after sorting

>>> l2 = [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)]
>>> get_first=key=lambda item: item[0]
>>> print [list(group) for _, group in groupby(sorted(l2,key=get_first), get_first)]
[[('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5), ('Yadda', 9)]]

      

  • You can also use a filter!


IN,

>>> l=[('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> s=set(map(lambda item: item[0],l))
>>> print [filter(lambda x:name in x,l) for name in s]
[[('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5), ('Yadda', 9)]]

      

  • You can also use itemgetter,

I.e

>>> l=[('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> from operator import itemgetter
>>> s=set(map(itemgetter(0),l))
>>> print [filter(lambda x:name in x,l) for name in s]
[[('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5), ('Yadda', 9)]]

      

+1


source


Assuming you are splitting the list based on the first element of the inner list, I would use a dictionary.

l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
d={}
for x in l:
  if x[0] not in d:
    d[x[0]]=[x]
  else:
    d[x[0]].append(x)
print(d.values())

      

0


source


I decided this way.

list = [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)]
ls_set = (set([ls[0] for ls in list]))
ls_dict = {}
for ls in ls_set:
    ls_dict[ls] = []
for ls in list:
    ls_dict[ls[0]].append(ls[1])
final_list = []
for key, value in ls_dict.items():
    a = []
    for i in value:
        a.append(tuple([key,i]))
    final_list.append(a)
print(final_list)

      

0


source


if you want without any package or itertools

then this will help you,

>>> l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> l.sort(key= lambda x:x[1])
>>> values = set(map(lambda x:x[0], l))
>>> [[y for y in l if y[0]==i] for i in values]
[[('Blah', 2), ('Blah', 4), ('Blah', 12)], [('Yadda', 5), ('Yadda', 9)]]
>>> 

      

0


source







All Articles