【问题标题】:Grouping a grouped list of str without duplicates对 str 的分组列表进行分组而不重复
【发布时间】:2021-11-16 12:14:59
【问题描述】:

我有一个字符串的分组列表,看起来像这样,这些组内的列表将始终包含 5 个元素:

text_list = [['aaa','bbb','ccc','ddd','eee'],
['fff','ggg','hhh','iii','jjj'],
['xxx','mmm','ccc','bbb','aaa'],
['fff','xxx','aaa','bbb','ddd'],
['aaa','bbb','ccc','ddd','eee'],
['fff','xxx','aaa','ddd','eee'],
['iii','xxx','ggg','jjj','aaa']]

目标很简单,将所有相似的列表按前 3 个元素分组,然后与其他组内的所有元素进行比较。

所以从上面的例子来看,输出可能是这样的(输出是列表的索引):

[[0,2,4],[3,5]]

请注意,如果另一个列表包含相同的元素但顺序不同,则如何删除。

我编写了以下代码来提取组,但它们会返回重复项,我不确定如何继续。我还认为这可能不是进行提取的最有效方法,因为实际列表可能包含数百万组:

grouped_list = []
for i in range(0,len(text_list)):
    int_temp = []
    for m in range(0,len(text_list)):
        if i == m:
            continue
        bool_check = all( x in text_list[m] for x in text_list[i][0:3])
        
        if bool_check:
            if len(int_temp) == 0:
                int_temp.append(i)
                int_temp.append(m)
                continue
            int_temp.append(m)
           
    
    grouped_list.append(int_temp)
    
## remove index with no groups
grouped_list = [x for x in grouped_list if x != []]

有没有更好的方法来解决这个问题?之后如何删除重复的组?谢谢。

编辑:

为了更清楚,我想检索彼此相似但仅使用其他列表的前 3 个元素的列表。例如,使用列表 A 中的前 3 个元素,检查列表 B、C、D... 是否包含列表 A 中的所有 3 个元素。重复整个列表,然后删除所有包含重复元素的列表。

【问题讨论】:

  • 您能否更清楚地了解以下语句的含义:“将所有相似的列表按前 3 个元素分组,然后与其他组内的所有元素进行比较”?
  • 除了让问题更清楚之外,请检查将grouped_list.append(int_temp) 更改为if not sorted(int_temp) in grouped_list and len(int_temp) > 0: grouped_list.append(sorted(int_temp)) 是否有效。
  • 感谢 iGian 的评论。我添加了一个解释。你的建议也成功了。

标签: python list optimization duplicates


【解决方案1】:

您可以构建一组 freezesets 来跟踪组的索引,其中前 3 个项目是其余成员的子集:

groups = set()
sets = list(map(set, text_list))
for i, lst in enumerate(text_list):
    groups.add(frozenset((i, *(j for j, s in enumerate(sets) if set(lst[:3]) <= s))))
print([sorted(group) for group in groups if len(group) > 1])

如果输入列表很长,创建所有子列表的前 3 项的一组 frozensets 并使用该集合过滤每个子列表中 3 项的所有组合会更快,这样尽管生成组合的开销很大,但时间复杂度基本上与输入列表呈线性关系,而不是二次的:

from itertools import combinations

sets = {frozenset(lst[:3]) for lst in text_list}
groups = {}
for i, lst in enumerate(text_list):
    for c in map(frozenset, combinations(lst, 3)):
        if c in sets:
            groups.setdefault(c, []).append(i)
print([sorted(group) for group in groups.values() if len(group) > 1])

【讨论】:

  • 我运行了您的代码,但它返回了 [[0, 4], [3, 5]] 而不是所需的输出 [[0,2,4],[3,5]]
  • 那是因为您的预期输出不正确。索引 2 ('xxx','mmm','ccc') 的子列表的前 3 项与索引 0 和 4 ('aaa','bbb','ccc') 的子列表不同。
  • 啊,对不起。我可能用错了这个问题的措辞。前 3 项用于与其他子列表中的所有元素进行比较。
  • 我总是忘记docs.python.org/3/library/stdtypes.html#dict.setdefault,提醒我一下。
  • @alD 我明白了。我已经相应地更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多