假设这个列表:
list1=["House of Mine (1293) Item 21",
"House of Mine (1292) Item 24",
"The yard (1000) Item 1 ",
"The yard (1000) Item 2 ",
"The yard (1000) Item 4 "]
如果直到 (XXXX) 的子字符串相同,我想将它的每个项目添加到一个组(在这种情况下是列表中的列表)。
所以,在这种情况下,我希望有:
[["House of Mine (1293) Item 21",
"House of Mine (1292) Item 24"],
["The yard (1000) Item 1 ",
"The yard (1000) Item 2 ",
"The yard (1000) Item 4 "]
下面的代码是我能够制作的,但它不起作用:
def group(list1):
group=[]
for i, itemg in enumerate(list1):
try:
group[i]
except Exception:
group.append([])
for itemj in group[i]:
if re.findall(re.split("\(\d{4}\)\(", itemg)[0], itemj):
group[i].append(itemg)
else:
group.append([])
group[-1].append(itemg)
return group
感谢堆栈中的另一个主题,正则表达式页面,我已经阅读了 http://www.diveintopython3.net/regular-expressions.html
我知道答案就在上面,但我很难理解它的一些概念。
请您参考如下方法:
设置要分组的列表:
>>> list1=["House of Mine (1293) Item 21","House of Mine (1292) Item 24", "The yard (1000) Item 1 ", "The yard (1000) Item 2 ", "The yard (1000) Item 4 "]
定义一个函数,用于对项目进行排序和分组(这次使用括号中的数字):
>>> keyf = lambda text: text.split("(")[1].split(")")[0]
>>> keyf
<function __main__.<lambda>>
>>> keyf(list1[0])
'1293'
对列表进行排序(在此处):
>>> list1.sort() #As Adam Smith noted, alphabetical sort is good enough
从 itertools 获取 groupby
>>> from itertools import groupby
检查概念:
>>> for gr, items in groupby(list1, key = keyf):
... print "gr", gr
... print "items", list(items)
...
>>> list1
['The yard (1000) Item 1 ',
'The yard (1000) Item 2 ',
'The yard (1000) Item 4 ',
'House of Mine (1292) Item 24',
'House of Mine (1293) Item 21']
请注意,我们必须对项目调用 list,因为 items 是项目的迭代器。
现在使用列表理解:
>>> res = [list(items) for gr, items in groupby(list1, key=keyf)]
>>> res
[['The yard (1000) Item 1 ',
'The yard (1000) Item 2 ',
'The yard (1000) Item 4 '],
['House of Mine (1292) Item 24'],
['House of Mine (1293) Item 21']]
我们完成了。
如果你想对第一个"("之前的所有文本进行分组,唯一的变化是:
>>> keyf = lambda text: text.split("(")[0]
简短版回答OP
>>> list1=["House of Mine (1293) Item 21","House of Mine (1292) Item 24", "The yard (1000) Item 1 ", "The yard (1000) Item 2 ", "The yard (1000) Item 4 "]
>>> keyf = lambda text: text.split("(")[0]
>>> [list(items) for gr, items in groupby(sorted(list1), key=keyf)]
[['House of Mine (1293) Item 21', 'House of Mine (1292) Item 24'],
['The yard (1000) Item 1 ',
'The yard (1000) Item 2 ',
'The yard (1000) Item 4 ']]
使用re.findall的变体
解决方案假定“(”是定界符,并忽略那里有四位数字的要求。这样的任务可以使用 re 解决。
>>> import re
>>> keyf = lambda text: re.findall(".+(?=\(\d{4}\))", text)[0]
>>> text = 'House of Mine (1293) Item 21'
>>> keyf(text)
'House of Mine '
但如果文本没有预期的内容(我们试图从空列表中访问索引为 0 的项目),它会引发 IndexError: list index out of range。
>>> text = "nothing here"
IndexError: list index out of range
我们可以使用简单的技巧,为了生存,我们附加原始文本以确保那里有东西:
>>> keyf = lambda text: (re.findall(".+(?=\(\d{4}\))", text) + [text])[0]
>>> text = "nothing here"
>>> keyf(text)
'nothing here'
使用re的最终解决方案
>>> import re
>>> from itertools import groupby
>>> keyf = lambda text: (re.findall(".+(?=\(\d{4}\))", text) + [text])[0]
>>> [list(items) for gr, items in groupby(sorted(list1), key=keyf)]
[['House of Mine (1292) Item 24', 'House of Mine (1293) Item 21'],
['The yard (1000) Item 1 ',
'The yard (1000) Item 2 ',
'The yard (1000) Item 4 ']]
