简体   繁体   中英

Merging sets within sets in Python

I have a set (any collection type will do for all I care) like this.

myset = {{a},{b},{c},{d,e}, {d,f}}

I am now trying to check whether two elements {a} and {d} exist in myset and if so merge {a} with {d,e}. If on the other hand I am checking {d} and {f}, then I will merge {d,e} and {d,f} to get {d,e,f}.

I will be grateful if any one shows me the direction towards the solution.

This might not be the most pythonic approach but it should work,let me know if it doesn't and I have done it for lists,you could do it for sets using a similar approach

def get_member(a,the_list):
    if a in the_list:
        return a
    else:
        for elem in the_list:
            if isinstance(elem,list):
                if a in elem:
                    return elem
    return None

def merge_member(a,b,the_list):
    get_member_a = get_member(a,the_list)
    get_member_b = get_member(b,the_list)
    if get_member_a and get_member_b:
        the_list.remove(get_member_a)
        the_list.remove(get_member_b)
        if isinstance(get_member_b,list):
            get_member_b.extend(get_member_a)
            the_list.append(get_member_b)
        elif isinstance(get_member_a,list):
            get_member_a.extend(get_member_b)
            the_list.append(get_member_a)
        else:
            the_list.append([get_member_b,get_member_a])
    return the_list

First of all: you cannot build a set of sets in python, as a set needs to contain hashable values while a set itself is not hashable .

But of course you could do the same with a list of of sets. The probably fastest and most pythonic solution should be like:

myset = [{1}, {2}, {3}, {4, 5}, {5, 6}]
merged_set = set().union(*myset)

(set.union cannot only be used with one parameter,but with any number of parameters )

I appears that we need to improve the merge_member block to handle such cases where we have [['a'],['b'],['c'],['d'],['e','f','g']], as the_list and we are looking for 'e' and 'f'.

def merge_member(a,b,the_list):
    get_member_a = get_member(a, the_list)
    get_member_b = get_member(b, the_list)
    if get_member_a and get_member_b:
        if get_member_a.__eq__(get_member_b):
           the_list.remove(get_member_a)
           if isinstance(get_member_b, list):
              the_list.append(get_member_b)
        else:
           the_list.remove(get_member_a)
           the_list.remove(get_member_b)
           if isinstance(get_member_b, list):
              get_member_b.extend(get_member_a)
              the_list.append(get_member_b)
           elif isinstance(get_member_a, list):
              get_member_a.extend(get_member_b)
              the_list.append(get_member_a)
           else:
              the_list.append([get_member_b,get_member_a])
    return the_list

You can use this method to merge a set list:

from functools import reduce # for python3
myset = [{'a'}, {'b'}, {'c'}, {'d','e'}, {'d','f'}] 
reduce(lambda x, y: {*x, *y}, myset)

output:

{'a', 'b', 'c', 'd', 'e', 'f'}

Solution for the question:

from functools import reduce # for python3
myset = [{'a'}, {'b'}, {'c'}, {'d','e'}, {'d','f'}]  # define your set list

def get_element_set(elem, myset):
    try:
        z = [x for x in myset if elem in x] 
        result = reduce(lambda x, y: {*x, *y}, z)
        return result
    except TypeError as e:
        print('Element "%s" is not exist in myset!' % elem)
        return {}

def merge_member(elem_list, myset):
    z = map(lambda elem: get_element_set(elem, myset), elem_list)
    result = reduce(lambda x, y: {*x, *y}, z)
    return result

Example:

get_element_set('d', myset) # {'d', 'e', 'f'}
get_element_set('g', myset) # Element "g" is not exist in myset! {}
merge_member(['f', 'd'], myset) # {'d', 'e', 'f'}
merge_member(['a', 'd'], myset) # {'a', 'd', 'e', 'f'}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM