将列表中的类似元素分组

时间:2016-10-02 16:39:42

标签: python list similarity

我有一个列表[ [0], [0,1], [1,2], [3] ],我正在尝试将类似的元素组合在一起。我需要输出为[ [0,1,2], [3] ]。这是对列表列表中的类似元素进行分组。有没有一种首选方法可以做到这一点?

3 个答案:

答案 0 :(得分:1)

您可以循环输入列表中的每个项目并构建组(根据需要):

def calculate_groups(data):
    if not data:
        return []
    groups = [set(data[0])]
    for item in data[1:]:
        item_set = set(item)
        for group in groups:
            if any(k in group for k in item):
                group.update(item_set)
                break
        else:
            groups.append(item_set)
    return [list(group) for group in groups]

最后使用setsanylist comprehension

示例:

>>> calculate_groups([ [0], [0,1], [1,2] ,[3] ])
[[0, 1, 2], [3]]

答案 1 :(得分:0)

我建议你使用一个集合列表,让我们称之为 results_list ,从空列表开始,然后在遍历输入列表的列表时填充它:对于每个项目输入列表的子列表,您必须检查它们是否属于results_list中的任何集合。如果它们都不属于您,则只需添加一个包含该子列表元素的新集。如果他们这样做,您必须修改 results_list 合并所有至少存在其中一个项目的集合,包括该集合中子集列表的所有项目。

def regroup(groups_list):
    results_list = [set(groups_list[0])]
    for sub_list in groups_list[1:]:
        current_items_set = set(sub_list)
        groups_to_merge = []
        for group in results_list:  
            if any(k in group for k in sub_list):
                groups_to_merge.append(group)
        if not groups_to_merge:
            # All of the items are new
            results_list.append(current_items_set)
        elif len(groups_to_merge) == 1:
            # Current items belong only to one of the existing groups
            groups_to_merge[0] = groups_to_merge[0].update(current_items_set)
        else:
            # The items belong to more than one group, merging is needed
            new_set = reduce(lambda x, y: x.union(y), groups_to_merge) or set()
            new_set.update(current_items_set)
            # The new results_list will have the new merged set, excluding the separated ones
            results_list = filter(lambda x: x not in groups_to_merge, results_list) + [new_set]

    return [sorted(x) for x in results_list]

示例:

input_list_1 = [[0], [0,1], [1,2], [3]]
regroup(input_list_1)
[[0, 1, 2], [3]]

input_list_2 = [[0], [0,1], [1,2], [3], [0, 3]]
regroup(input_list_2)
[[0, 1, 2, 3]]

答案 2 :(得分:0)

这是另一个。比其他解决方案略短。

def get_cliques(groups):
    cliques = {}
    for g in groups:
        g = {*g}.union(*(cliques.get(i, []) for i in g))
        cliques.update({i: g for i in g})
    return {id(c): c for c in cliques.values()}.values()

这段代码背后的想法很简单:来自一个集团的元素将始终共享clique集合对象。集合将包含已知在相应集团中的所有元素。所以最后我们只需要从cliques字典中获取唯一的设置对象。我们使用内置id函数来返回对象内存地址(在CPython中):来自cliques字典中相同clique的不同元素包含相同的set对象,因此我们可以压缩cliques dict进入一个较小的值,这个值将是唯一的。