Skip to content Skip to sidebar Skip to footer

Pythonic Way To Split A List After Elements For Which A Given Predicate Is True

Assume you have a list of arbitrary elements like ['monkey', 'deer', 'lion', 'giraffe', 'lion', 'eagle', 'lion', 'fish'] which should be split into sublists after each element for

Solution 1:

The easiest way is probably:

out = [[]]for element in lst:
    out[-1].append(element)
    if predicate(element):
        out.append([])

Note that this would leave an empty list at the end of out, if predicate(element): for the last element. You can remove this by adding:

out = [l for l inoutif l]

Solution 2:

Just because we can, a functional one-liner:

from functools import reduce

reduce(lambda out, x: out[:-1] + [out[-1] + [x]] ifnot predicate(x) else out + [[x]], x, [[]])

Solution 3:

I rather like this solution:

def f(outs, x):
    if outs[-1][-1:] == ["lion"]:
        outs.append([])
    outs[-1].append(x)
    return outs

def splitAfterLion(xs):
    return reduce(f,xs,[[]])

It might not be very pythonic, more functional. But it's short and does not suffer from trailing empty lists in the result.

Solution 4:

>>> import itertools
>>> l = ['monkey', 'deer', 'lion', 'giraffe', 'lion', 'eagle', 'lion', 'fish']
>>> f = lambda i: i == "lion">>> a = [list(j) for i, j in itertools.groupby(l, f)]
>>> a
[['monkey', 'deer'], ['lion'], ['giraffe'], ['lion'], ['eagle'], ['lion'], ['fish']]
>>> [i+j for i, j inzip(a[::2], a[1::2])]
[['monkey', 'deer', 'lion'], ['giraffe', 'lion'], ['eagle', 'lion']]

Edit:

>>> [i+j for i, j in itertools.zip_longest(a[::2], a[1::2], fillvalue=[])]
[['monkey', 'deer', 'lion'], ['giraffe', 'lion'], ['eagle', 'lion'], ['fish']]

Solution 5:

Just another way of doing it by getting the index without using itertool, please let me know if that works for you:

#!/usr/bin/python

ls = ['monkey', 'deer', 'lion', 'giraffe', 'lion', 'eagle', 'lion', 'fish', 'fish']

defis_lion(elm):
    return elm in ls

defmark_it(nm):
    ind = [ x+1for x,y inenumerate(ls) if y == nm ]
    if ind[-1] < len(ls):
        ind.append(len(ls))
    return ind

defmerge_it(ind):
    return [list(ls[x[0]:x[1]]) for x inzip(ind[::], ind[1::])]

name = 'lion'if is_lion(name):
    index = [0]
    index.extend(mark_it(name))
    print merge_it(index)
else:
    print'not found'

Output:

[['monkey', 'deer', 'lion'], ['giraffe', 'lion'], ['eagle', 'lion'], ['fish', 'fish']]

Post a Comment for "Pythonic Way To Split A List After Elements For Which A Given Predicate Is True"