是否有更多Pythonic方式有条件地合并相邻的列表元素?

时间:2014-12-13 19:36:35

标签: python

假设我有以下列表。

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

我想将以\结尾的任何元素与其右侧的元素合并,删除过程中的\,然后继续执行此操作,直到没有更多元素带尾随\

正确的输出如下所示。

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

这是我目前的解决方案,它是功能性的,但似乎比必要的复杂得多。

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

tmpItem = None
tmpList = []

for x in myList:
   if tmpItem:
     if tmpItem.endswith("\\"):
        tmpItem = tmpItem[:-1] + x
     else:
        tmpList.append(tmpItem)
        tmpItem = x
   else: tmpItem = x

if tmpItem:
     if tmpItem.endswith("\\"):
        tmpList.append(tmpItem[:-1])
     else:
        tmpList.append(tmpItem)

print tmpList

有没有更简洁的方法在Python中执行此操作,可能使用更实用的习惯用法?

我看了reduce(),但似乎只允许你将一个减少从一个列表移动到一个元素,而不是另一个列表,但也许我低估了它的力量。

5 个答案:

答案 0 :(得分:3)

不确定是否有更多的pythonic,但肯定更简洁。

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

如果您无法假设字符串不包含\0,则可以生成分隔符:

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

答案 1 :(得分: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

打印

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

答案 2 :(得分:1)

如果这对你来说是pythonic:

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

我觉得理解它很酷很有用(即使不使用)

说明:使用reduce中的聚合列表,并在需要时回溯到要追加的最后一个元素。否则附加到列表。不回头看第一个元素以避免异常。

  

['回显FooBar和更多的foos',' cat / etc / cpuinfo',' cat / path / to / long / deep / directory / that / goes /上/永远']

答案 3 :(得分:0)

可能更容易阅读的解决方案是

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

对我而言,这更容易阅读,因为wp“写指针”模式来修改数组,这是我手指上的东西。可读性在旁观者的眼中......

纯粹的功能性解决方案(根本没有任务)可能

def merge_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)

但它确实不属于Python。

另一个版本可以写成生成器,接受任何可迭代:

def merge_continuations(it):
    prefix = None
    for L in it:
        if prefix is None:
            prefix = L
        elif prefix.endswith('\\'):
            prefix = prefix[:-1] + L
        else:
            yield prefix
            prefix = L
    if prefix is not None:
        yield prefix

不是我喜欢的方法,而是Python中的惯用法

答案 4 :(得分:0)

它可能不是最短的,但它具有相当的可读性和Pythonic。

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

print(out)