当输出依赖于其他元素时,以Python方式对列表进行操作
我有一个任务需要对列表中的每个元素进行操作,操作的结果取决于列表中的其他元素 例如,我可能希望将以特定字符开头的字符串列表连接起来: 此代码解决了以下问题:当输出依赖于其他元素时,以Python方式对列表进行操作,python,Python,我有一个任务需要对列表中的每个元素进行操作,操作的结果取决于列表中的其他元素 例如,我可能希望将以特定字符开头的字符串列表连接起来: 此代码解决了以下问题: x = ['*a', 'b', 'c', '*d', 'e', '*f', '*g'] concat = [] for element in x: if element.startswith('*'): concat.append(element) else: concat[len(conca
x = ['*a', 'b', 'c', '*d', 'e', '*f', '*g']
concat = []
for element in x:
if element.startswith('*'):
concat.append(element)
else:
concat[len(concat) - 1] += element
导致:
concat
Out[16]: ['*abc', '*de', '*f', '*g']
>>> print(grouped)
[['*a', 'b', 'c'], ['*d', 'e'], ['*f'], ['*g']]
但这似乎是可怕的非蟒蛇。当操作结果取决于之前的结果时,应如何操作列表中的元素
"".join(x).split("*")
也许足够了,当然,这可能是您的OP中的一个人为的例子,过于简单,因此这将不起作用您可以使用正则表达式简洁地完成这一点。然而,这在某种程度上绕过了关于如何操作依赖列表元素的问题。为改进允许的字符功能而授予的学分
import re
z = re.findall('\*[^*]+',"".join(x))
输出:
['*abc', '*de', '*f', '*g']
小型基准测试:
['*abc', '*de', '*f', '*g']
:
分别返回0.002641693456
和0.06827958075
:
分别返回0.00456210269896
和0.364635824689
分别返回0.00104848906006
和0.0556093171512
tl;Saksham博士的比我的稍快一点,然后Chepner的跟在我们后面 来自的一些相关摘录导入了这个(什么是Pythonic的仲裁者):
- 简单胜于复杂
- 可读性计数
- 显式比隐式好
我只会使用这样的代码,而不用担心用“更平坦”的东西替换for循环
这个怎么样:
>>> x = ['*a', 'b', 'c', '*d', 'e', '*f', '*g']
>>> print ['*'+item for item in ''.join(x).split('*') if item]
['*abc', '*de', '*f', '*g']
我觉得这很像蟒蛇:
# assumes no empty strings, or no spaces in strings
"".join(x).replace('*', ' *').split()
以下是一种功能性方法:
from functools import reduce
# assumes no empty strings
def reduction(l, it):
if it[0] == '*':
return l + [it]
else:
new_l, last = l[:-1], l[-1]
return new_l + [last + it]
x = ['*a', 'b', 'c', '*d', 'e', '*f', '*g']
print reduce(reduction, x, [])
>>> ['*abc', '*de', '*f', '*g']
如果您是lambdas的粉丝(不太像蟒蛇),您可以这样做:
# Don't do this, it's ugly and unreadable.
reduce(lambda l, it: l + [it] if it.startswith('*') else l[:-1] + [l[-1]+it], x, [])
这与实际情况非常接近,事实上,只要加上一点咖喱,我就可以让它一直分组,直到出现“中断”情况,例如startswith('*')
导致:
concat
Out[16]: ['*abc', '*de', '*f', '*g']
>>> print(grouped)
[['*a', 'b', 'c'], ['*d', 'e'], ['*f'], ['*g']]
当然,nonlocal
关键字需要Python3。另一种可能是按照itertools文档中的groupby
“等效代码”创建一个类
我不知道这比你的代码更像python,但我认为去标准库看看是否有什么东西几乎符合你的需要是一个有用的观点。同意在这个特定(但有些虚构)的例子中这看起来很棒。(虽然它不能完全再现输出。OP中的星星被保留。)但是,通过这个例子,关于Python编码还有什么更通用的东西可以学习吗?也许有不止一种方法可以剥猫皮?如果有一个不那么虚构的例子,我相信我们可以找到同样清晰的东西…在这个基础上,我们来看看列表(map(lambda v:'*'+v,“.”.join(x).split('*')[1:])
?否。。。那倒过来了。。。如果你真的需要它,[“*”+x代表新列表中的x]
难以置信。。。有人真的给了我-1,因为我没有“*”?只需注意:第二个星号前面的\
是可选的,因为它包含在字符类中。如果你不想,你不需要编辑它+1感谢您将讨论带回到“pythonic”,远离整洁/紧凑/快速。如果您感兴趣,请将您的答案添加到我的小基准中:)我在大量输入上的缓慢时间并不让我感到惊讶:)但是,如果x
真的那么大,我会在构建x
时研究构建concat
,而不是等到x
完成后才开始。@chepner这是有道理的。我只是觉得我应该加上它来取乐+感谢您摘自python的zen,但是您真的认为这个复杂的循环和隐式算法在可读性方面更好吗?特别是那些额外的部分数组在我看来似乎比OP的代码更糟糕。在我看来,这是最好的答案+1heh这几乎和我的答案一样:P他只是在修正输出,但是的+1好答案imho:)
from itertools import groupby
def new_group_when_true(pred):
group_num = 0
def group_for_elem(elem):
nonlocal group_num
if pred(elem):
group_num +=1
return group_num
return group_for_elem
l = ['*a', 'b', 'c', '*d', 'e', '*f', '*g']
test = new_group_when_true(lambda elem: elem.startswith('*'))
grouped = [list(v) for k,v in groupby(l, test)]
>>> print(grouped)
[['*a', 'b', 'c'], ['*d', 'e'], ['*f'], ['*g']]