不仅是多组的交集,还有联合和更新

时间:2018-05-05 04:38:10

标签: python python-3.x

我试图在python中找到两个sets之间的交集。但是,一旦找到,我需要union两个集合并再次在dictionary上迭代,直到没有进一步的变化。

类似的东西:

dict_={'a': {1,3,4}, 'b': {0,5,4}, 'c': {0,6,5},'e':{7,9}}

我需要什么:

result={'abc':{1,3,4,0,5,4,0,6,5}, 'e':{7,9}}

这是我到目前为止做了什么:

dict_={'a': {1,3,4}, 'b': {0,5,4}, 'c': {0,6,5},'e':{7,9}}    
flag=True
while flag:
    done=False
    for key in list(dict_):
        if done:        ## to break outer loop
            del dict_[remove1]
            del dict_[remove2]
            break
        for newKey in list(dict_):
            if key==newKey:
                continue
            if len(set.intersection(dict_[key],dict_[newKey]))>0:
                added_key=str(key)+str(newKey)
                dict_[added_key]=set.union(dict_[key],dict_[newKey])
                remove1=key
                remove2=newKey
                done=True
                break    ## to break inner loop
    flag=False     ## Here is the problem. I do not know what to do

此代码的结果:

dict_
#{'ab': {0, 1, 3, 4, 5}, 'c': {0, 5, 6}, 'e': {7, 9}}

3 个答案:

答案 0 :(得分:1)

正如有人在评论中指出的那样,您所需的输出设置无效。假设你想加入密钥并联合值集,直到它们有任何共同点,你可以这样做:

d ={'a': {1,3,4}, 'b': {0,5,4}, 'c': {0,6,5},'e':{7,9}}

flag = True

while (flag):
    keys = list(d.keys())
    outer_break = False
    for i in range(len(keys)-1):
        inner_break = False
        for j in range(i+1, len(keys)):
            if len(set.intersection(d[keys[i]], d[keys[j]])) > 0:
                d[keys[i] + keys[j]] = set.union(d[keys[i]], d[keys[j]])
                del d[keys[i]]
                del d[keys[j]]
                inner_break = True
                break
        if inner_break:
            outer_break = True
            break
    if not outer_break:
        flag = False

print (d)
# {'e': {9, 7}, 'cab': {0, 1, 3, 4, 5, 6}} 

您也可以使用这样的递归函数执行此操作:

dd ={'a': {1,3,4}, 'b': {0,5,4}, 'c': {0,6,5},'e':{7,9}}

def reduce_dict(d):
    keys = list(d.keys())
    for i in range(len(keys)-1):
        for j in range(i+1, len(keys)):
            if len(set.intersection(d[keys[i]], d[keys[j]])) > 0:
                d[keys[i] + keys[j]] = set.union(d[keys[i]], d[keys[j]])
                del d[keys[i]]
                del d[keys[j]]
                return reduce_dict(d)
    return d

dd = reduce_dict(dd)

print(dd)
# {'e': {9, 7}, 'cab': {0, 1, 3, 4, 5, 6}} 

答案 1 :(得分:1)

我建议使用itertools.combinations来查看所有可能的唯一键组合,您可以避免使用这么多标志,而是以这种方式使用看到的set():

from itertools import combinations

dict_={'a': {1,3,4}, 'b': {0,5,4}, 'c': {0,6,5},'e':{7,9}}

for i in range(2,len(dict_)+1): # For length of dict from 2
    # Initialize the "seen" list
    seen_keys = set()
    for combination in list(combinations(dict_, 2)): # Get possible key combinations of 2
            keys_in_combination = [dict_[x] for x in combination] # And their values in a list

            if len(set.intersection(*keys_in_combination)): # * Expands the list into the arguments
                # Make key names alphabetical with no duplicate letters.
                added_key = "".join(sorted(set(x for y in combination for x in str(y))))
                # Join 2 sets under new key
                dict_[added_key] = set.union(*keys_in_combination)
                for seen_key in combination:
                    # create a seen list (for the deletion below)
                    seen_keys.add(seen_key)

    # Delete the keys which have been joined to others
    for key in dict_.copy():
        if len(key) < i and key in seen_keys:
            del dict_[key]

print(dict_)

结果:

{'abc': set([0, 1, 3, 4, 5, 6]), 'e': set([9, 7])}

此方法也适用于组合可能长于&#34; abc&#34;

的词组。

答案 2 :(得分:0)

一种非常优化的方法是使用一系列的项目 并循环遍历列表,然后递归更新项目 有任何交集。

def find_intersection(m_list):
    for i, (key_1, v) in enumerate(m_list) : 
        for j, (key_2, k) in enumerate(m_list[i+1:],i+1):
        if v & k:
            m_list[i] = key_1 + key_2, v.union(m_list.pop(j)[1])
            return find_intersection(m_list)
    return m_list

演示:

In [10]: find_intersection(list(mydict.items()))
Out[10]: [('abc', {0, 1, 3, 4, 5, 6}), ('e', {7, 9})]