Skip to main content
 首页 » 编程设计

python之在 python 中按字符串模式对项目进行分组

2025年05月04日21lhb25

假设这个列表:

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 ']]