How to merge sets which have intersections (connec

2020-02-01 02:19发布

Is there any effective way to merge sets which have intersections. For example:

l = [{1, 3}, {2, 3}, {4, 5}, {6, 5}, {7, 5}, {8, 9}]

The expected result is:

r = [{1, 2, 3}, {4, 5, 6, 7}, {8, 9}]

All sets which have intersection (common components) should be merged. For example:

{1, 3} & {2, 3}
# {3}

So these two sets should be merged:

{1, 3} | {2, 3}
# {1, 2, 3}

Unfortunately I don't have any working solution.

UPDATE: The order of sets in the result is not important.

2条回答
Rolldiameter
2楼-- · 2020-02-01 03:11

An efficient way to implement the connected components algorithm as mentioned by @mkrieger1 in the comments is to convert the list of sets to a set of hashable frozensets so that as you iterate through it and find a frozenset that intersects with the current one you can easily remove it from the pool:

pool = set(map(frozenset, l))
groups = []
while pool:
    groups.append(set(pool.pop()))
    while True:
        for candidate in pool:
            if groups[-1] & candidate:
                groups[-1] |= candidate
                pool.remove(candidate)
                break
        else:
            break

Given l = [{1, 3}, {2, 3}, {4, 5}, {6, 5}, {7, 5}, {8, 9}], groups will become:

[{1, 2, 3}, {4, 5, 6, 7}, {8, 9}]

And given l = [{1, 2}, {3, 4}, {2, 3}], groups will become:

[{1, 2, 3, 4}]

And given l = [{1}, {2}, {1, 2}], groups will become:

[{1, 2}]
查看更多
等我变得足够好
3楼-- · 2020-02-01 03:20

I propose this solution:

def merge_sets(set_list):
    if len(set_list) == 0:
        # short circuit to avoid errors
        return []

    current_set = set_list[0]
    new_set_list = [current_set, ]

    for s in set_list[1:]:          # iterate from the second element
        if len(current_set.intersection(s)) > 0:
            current_set.update(s)
        else:
            current_set = set(s)    # copy
            new_set_list.append(current_set)

    return new_set_list

The test cases this works for:

test_cases = [
    {
        'input': [{1, 3}, {2, 3}, {4, 5}, {6, 5}, {7, 5}, {8, 9}],
        'output': [{1, 2, 3}, {4, 5, 6, 7}, {8, 9}],
    },
    {
        'input': [{1, 2}, {2, 3}, {3, 4}],
        'output': [{1, 2, 3, 4}, ],
    },
    {
        'input': [{1}, {2}, {1, 2}],
        'output': [{1}, {1, 2}],
    },
    {
        'input': [{1, 2}, {3, 4}, {2, 3}],
        'output': [{1, 2}, {2, 3, 4}],
    },
]

for case in test_cases:
    print('input   ', case['input'])
    print('expected', case['output'])

    new_output = merge_sets(case['input'])
    print('real    ', new_output)
    assert new_output == case['output']

Does this work for you?

查看更多
登录 后发表回答