【问题标题】:Splitting a list by matching a regex to an element通过将正则表达式与元素匹配来拆分列表
【发布时间】:2014-11-18 20:00:17
【问题描述】:

我有一个包含一些特定元素的列表。我想根据这些元素将该列表拆分为“子列表”或不同的列表。例如:

test_list = ['a and b, 123','1','2','x','y','Foo and Bar, gibberish','123','321','June','July','August','Bonnie and Clyde, foobar','today','tomorrow','yesterday']

如果元素匹配“某事某事”,我想拆分为子列表:

new_list = [['a and b, 123', '1', '2', 'x', 'y'], ['Foo and Bar, gibberish', '123', '321', 'June', 'July', 'August'], ['Bonnie and Clyde, foobar', 'today', 'tomorrow', 'yesterday']]

到目前为止,如果在特定元素之后有固定数量的项目,我可以做到这一点。例如:

import re
element_regex = re.compile(r'[A-Z a-z]+ and [A-Z a-z]+')
new_list = [test_list[i:(i+4)] for i, x in enumerate(test_list) if element_regex.match(x)]

几乎就在那里,但并不总是紧跟在特定的感兴趣元素之后的三个元素。有没有比循环遍历每个项目更好的方法?

【问题讨论】:

  • 看起来您想在'Foo and Bar, gibberish' 上拆分,但您的正则表达式将不匹配(它会在 Bar 之后的逗号上失败)。您是否在任何地方都缺少单引号? 'Bonnie and Clyde, foobar' 有同样的问题。至于更好的方法,除非您不能连续匹配两个匹配项或存在其他限制,否则您确实需要检查每个条目,因为它可能是新列表的开始。

标签: python regex list


【解决方案1】:

如果你想要单线,

new_list = reduce(lambda a, b: a[:-1] + [ a[-1] + [ b ] ] if not element_regex.match(b) or not a[0] else a + [ [ b ] ], test_list, [ [] ])

会的。但是,python way 将使用更详细的变体。

我在 4 核 i7 @ 2.1 GHz 上进行了一些速度测量。 timeit 模块运行此代码 1.000.000 次,为此需要 11.38 秒。使用来自 itertools 模块的groupby(来自另一个答案的 Kasras 变体)需要 9.92 秒。最快的变种是我建议的详细版本,只用了 5.66 秒:

new_list = [[]]
for i in test_list:
    if element_regex.match(i):
        new_list.append([])
    new_list[-1].append(i)

【讨论】:

  • 虽然不是很pythonic,但这就是我想要的。
【解决方案2】:

你不需要regex,只需使用itertools.groupby

>>> from itertools import groupby
>>> from operator import add
>>> g_list=[list(g) for k,g in groupby(test_list , lambda i : 'and' in i)]
>>> [add(*g_list[i:i+2]) for i in range(0,len(g_list),2)]
[['a and b, 123', '1', '2', 'x', 'y'], ['Foo and Bar, gibberish', '123', '321', 'June', 'July', 'August'], ['Bonnie and Clyde, foobar', 'today', 'tomorrow', 'yesterday']]

首先我们通过这个 lambda 函数 lambda i : 'and' in i 对列表进行分组,它会找到其中包含 "and" 的元素!然后我们有这个:

>>> g_list
[['a and b, 123'], ['1', '2', 'x', 'y'], ['Foo and Bar, gibberish'], ['123', '321', 'June', 'July', 'August'], ['Bonnie and Clyde, foobar'], ['today', 'tomorrow', 'yesterday']]

所以我们必须在这里连接我们使用add 运算符和列表推导的两对列表!

【讨论】:

  • 谢谢!我和菲利普斯一起回答了单线问题。但是您现在已经说服我阅读更多有关 itertools 的内容。似乎 itertools 是我大多数 python 问题的答案。
  • 是的,itertools 是 python 模块中的传奇!但关于一个班轮不要确定它更快! ;)
  • 这两种变体在速度方面没有太大区别。在我的 PC 上,speedit 使用 reduce() 运行 1M 需要 11.38 秒,而 itertools 变体需要 9.92 秒(如果还使用正则表达式)。我更喜欢您的变体的原因是更好的可读性。而且我认为我仍然更喜欢for 循环而不是两者。我会在我的答案中添加一些内容。
  • @Phillip 当问题与处理列表有关时,我首先想到的是itertools! ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多