Skip to content Skip to sidebar Skip to footer

Is There A More Pythonic Way To Conditionally Merge Adjacent List Elements?

Suppose I have the following list. myList = ['echo FooBar \\', 'and some more foos', 'cat /etc/cpuinfo', 'cat /path/to/\\', 'long/deep/directory/\\', 'that/goes/on/forever']

Solution 1:

Not sure if more pythonic, but certainly more concise.

"\0".join(myList).replace("\\\0","").split("\0")

If you can't make assumptions that the strings don't include \0 you can generate the separator:

import string
import random
sep = ""whileany(sep in s for s in myList):
    sep += random.choice(string.ascii_uppercase + string.digits)
sep.join(myList).replace("\\"+sep,"").split(sep)

Solution 2:

myList = ["echo FooBar \\", "and some more foos", "cat /etc/cpuinfo", 
    "cat /path/to/\\", "long/deep/directory/\\", "that/goes/on/forever"]
ret = []
for i in myList:
    if ret and ret[-1].endswith('\\'):
        ret[-1] = ret[-1][:-1] + i
    else:
        ret.append(i)

print ret

prints

['echo FooBar and some more foos', 'cat /etc/cpuinfo',
 'cat /path/to/long/deep/directory/that/goes/on/forever']

Solution 3:

If this is pythonic for you:

reduce(lambda agg, x: (agg +
                        [agg.pop()[:-1] + x] if agg[-1].endswith('\\') else
                         agg + [x]) if len(agg) > 0 else
                         agg + [x], myList, [])

I think it's cool and useful to understand (even if not to use)

Explanation: uses the aggregated list in reduce and looks back to the last element to append to it if needed. Otherwise appends to list. Doesn't look back on first element to avoid exception.

['echo FooBar and some more foos', 'cat /etc/cpuinfo', 'cat /path/to/long/deep/directory/that/goes/on/forever']

Solution 4:

A possibly easier to read solution is

wp = 0for L in myList:
    if wp and myList[wp - 1].endswith('\\'):
        myList[wp - 1] = myList[wp - 1][:-1] + L
    else:
        myList[wp] = L
        wp += 1del myList[wp:]

For me this is easier to read because the wp "write-pointer" pattern to modify arrays inplace is something that I've in the fingers. Readiility is in the eye of the beholder...

A purely functional solution (no assignments at all) could be

defmerge_continuations(L, ix=0):
    if ix >= len(L)-1:
        return L
    elif L[ix].endswith('\\'):
        return merge_continuations(L[:ix] +
                                   [L[ix][:-1] + L[ix+1]] +
                                   L[ix+2:], ix)
    else:
        return merge_continuations(L, ix+1)

but it really doesn't belong to Python.

Another version could be written as a generator, accepting any iterable:

defmerge_continuations(it):
    prefix = Nonefor L in it:
        if prefix isNone:
            prefix = L
        elif prefix.endswith('\\'):
            prefix = prefix[:-1] + L
        else:
            yield prefix
            prefix = L
    if prefix isnotNone:
        yield prefix

not my preferred approach, but idiomatic in Python

Solution 5:

It may not be the shortest, but it's fairly readable and Pythonic.

out, grp = [], []
for s in my_list:
    if s.endswith('\\'):
        grp.append(s[:-1])
    else:
        out.append(''.join(grp) + s)
        grp = []

print(out)

Post a Comment for "Is There A More Pythonic Way To Conditionally Merge Adjacent List Elements?"