Welcome, guest | Sign In | My Account | Store | Cart

Search for the separator sep in string s, and return the part before it, the separator itself, and the part after it continuously untill all the seperator finishes. If the separator is not found, return string s. It works like split() combined with partition()

Python, 17 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def partitionall(s, sep=None):
    """
    Search for the separator sep in string s, and return the part before it,
    the separator itself, and the part after it continuously untill all the 
    seperator finishes. If the separator is not found, return string s.
    It works like split() combined with partition()  
    """
    ls = s.split(sep)
    nls = [sep] * (len(ls) * 2 - 1)
    nls[::2] = ls
    return nls

if __name__ == "__main__":
    s = 'This is a, test for, all partition,,'
    sep = ','
    print partitionall(s, sep)
    # result = ['This is a', ',', ' test for', ',', ' all partition', ',', '', ',', '']

4 comments

Gabriel Genellina 14 years ago  # | flag

I don't see why you chose to filter out the empty parts - leaving them in the output makes it more regular and predictable, and is conforming to the function docstring.

Also, using a list comprehension as if it were a for-loop, just for the side effects, is considered bad form.

@Gabriel Thanks for the comment. I had modified the code so as to return the empty parts as happens in .split(). However the list comprehension I had used is compact and clear. If only you could mention the side-effects I will happily change it to a for loop. :)

Matthew Wood 14 years ago  # | flag

Ooooh, this is a fun problem! On my system, I got MUCH better speed if I used python's slicing replace, instead of inserting the 'sep' in every other element. This was especially the case for strings with many instances of 'sep':

def partitionall(s, sep):
    ls = s.split(sep)
    nls = [sep] * (len(ls) * 2 - 1)
    nls[::2] = ls
    return nls

Granted, I also make a copy of the list, but you are also silently making a copy as well with the use of the list comprehension.

[ls.insert(2*i+1, sep) for i in range(len(ls) - 1)]

Try printing that line, you should get this: [None, None, None, None]

That's because you are actually constructing a list in that comprehension, and it's going to take up memory. That's one of the reasons Gabriel said that it's bad form to use a list comprehension in place of a standard for-loop.

For what it's worth, what Gabriel meant by "side effects" is this:

for a in range(6):
    sys.stdout.write('%s\n' % a)

That code prints all 6 numbers, and it doesn't return a list of something.

[sys.stdout.write('%s\n' % a) for a in range(6)]

This code also prints out all 6 numbers. But a list comprehension is supposed to construct a list, while a for-loop simply iterates over an existing list. Using a list comprehension to create an effect other than constructing a new list, has unforeseen consequences. When he says "side effects" he's referring to these "non-construction effects".

In the example I gave above, I've actually created a 6 element list as you can see here:

[sys.stdout.write('%s\n' % a) for a in range(4)] 0 1 2 3 4 5 [None, None, None, None, None, None]

The list of "None"s is actually constructed.

And on a very minor side note: My system tests very slightly faster if I use a filter to remove empty parts:

[i for i in ls if i]

Is the equivalent of:

filter(bool, ls)

But that's pretty damn minor. :-)

@Matthew Thanks for the comment. I verified using slices and there was a definite improvement in speed.

while a for-loop simply iterates over an existing list. Using a list comprehension to create an effect other than constructing a new list, has unforeseen consequences.

This should be remembered while implementing list-comprehension, a side-effect of list-comprehension for sure.

However using filter when list-comprehension suffice is not preferred by python community, so for such cases am sticking with list-comprehensions. Edited the recipe, in favor of your example.

Created by Shashwat Anand on Sun, 21 Feb 2010 (MIT)
Python recipes (4591)
Shashwat Anand's recipes (3)

Required Modules

  • (none specified)

Other Information and Tasks