Ilya V. Schurov
Ilya V. Schurov

Reputation: 8047

Pythonic way to split list into parts by conditionaly-given delimeter

I have a list and I want to split it into parts moslty like str.split() works for strings with the following differences:

  1. The delimiter is given by predicate. If predicate is True for element of the list, this element is considered as a delimeter.
  2. I want to keep the delimeter in the resulting lists.

For example:

split_by_predicate([0, "One", 1, 2, 3, 
                    "Two", 4, 5, 6, 7, "Three", "Four"],
                    predicate=lambda x: isinstance(x, str))

should give me

[[0], ["One", 1, 2, 3], ["Two", 4, 5, 6, 7], ["Three"], ["Four"]]

I can write the following code:

def split_by_predicate(it, predicate):
    lst = []
    cur = []
    for element in it:
       if predicate(element):
          lst.append(cur)
          cur = []
       cur.append(element)
    lst.append(cur)
    return lst

But I find it not elegant and not Pythonic. A similar approach is given here (using generators).

I tried to figure out some kind of itertools-based solution like this one, but they don't work well if the delimeter is repeated (like in my example).

Are there any ideas how to do it in more functional style than my current code?

Upvotes: 1

Views: 86

Answers (2)

Yaroslav Surzhikov
Yaroslav Surzhikov

Reputation: 1608

You can simplify your function to this:

def split_by_predicate(it, predicate):
    lst = [[]]
    for element in it:
        if predicate(element):
            lst.append([])
        lst[-1].append(element)
    return lst

Or this ( with skiped appending empty list on first iteration ):

def split_by_predicate(it, predicate):
    lst = [[]]
    for i, element in enumerate(it):
        if predicate(element) and i:
            lst.append([])
        lst[-1].append(element)
    return lst

Upvotes: 5

Nick is tired
Nick is tired

Reputation: 7055

What about this:

def split_by_predicate(it, predicate):
  o = []
  for i in it:
    if predicate(i) or len(o) == 0:
      o += [[i]]
    else:
      o[-1] += [i]
  return o

Output:

>>> split_by_predicate([0, 'One', 1, 2, 3, 'Two', 4, 5, 6, 7, 'Three', 'Four'], lambda x: isinstance(x,str))
[[0], ['One', 1, 2, 3], ['Two', 4, 5, 6, 7], ['Three'], ['Four']]

Upvotes: 1

Related Questions