给出s1,s2,s3,s4和s5:
s1 = {0: (0,), 1: (0,), 2: (1,)}
s2 = {0: (1,), 1: (0,), 2: (2,)}
s3 = {0: (1, 0), 1: (0,), 2: (2,)}
s4 = {0: (0, 1), 1: (1, 2), 2: (2, 3), 4: (4,)}
s5 = {0: (0, 1), 1: (1, 2), 2: (2, 3), 4: (4, 1)}
我可以使用什么函数分别将它们分别转换为r1,r2,r3,r4或r5:
r1 = {(0, 1): {0}, (2,): {1}}
r2 = {(2,): {2}, (0,): {1}, (1,): {0}}
r3 = {(0, 1): {0, 1}, (2,): {2}}
r4 = {(0, 1, 2): {0, 1, 2, 3}, (4,): {4}}
r5 = {(0, 1, 2, 4): {0, 1, 2, 3, 4}}
完成键的分组,以便sum(len(k) for k in r) == len(set.union(*r))
为True
,其中r为r1至r5。
这是一种蛮力解决方案,但我想看看其他方法:
def combinations(segment):
if len(segment) == 1:
yield (segment,)
else:
for x, j in enumerate(combinations(segment[1:])):
yield ((segment[0],),)+j
for k in range(len(j)):
yield (((segment[0],)+j[k]),) + (j[:k]) +(j[k+1:])
def sub_combinations(segment):
yield from filterfalse(lambda x: x == (segment,), combinations(segment))
def no_common_elements(sets):
return sum(len(s) for s in sets) == len(set.union(*sets))
def get_mutually_exclusive_groups(d):
for i in sub_combinations(tuple(d.keys())):
r = dict(((j, set.union(*[set(d[k]) for k in j])) for j in i) )
if no_common_elements(r.values()):
return r
return { tuple(set([ k for k in d])): set.union(*([ set(d[k]) for k in d])) }
inputs = [
{0: (0,), 1: (0,), 2: (1,)},
{0: (1,), 1: (0,), 2: (2,)},
{0: (1,0), 1: (0,), 2: (2,)},
{0:(0,1), 1:(1,2), 2: (2,3), 4: (4,)},
{0:(0,1), 1:(1,2), 2: (2,3), 4: (4,1)}
]
for input in inputs:
print(input)
print(get_mutually_exclusive_groups(input))
print()
答案 0 :(得分:0)
您可以使用itertools.groupby
。另外,要检查每个元组中的所有元素是否都出现在另一个元组中,请创建包装器class
:
import itertools
class _elem:
def __init__(self, *_k_v):
self._k, self._v = _k_v
def __eq__(self, elem):
return all(i in elem._v for i in self._v) or all(i in self._v for i in elem._v)
def group_vals(d:dict) -> dict:
_sort = sorted(d.items(), key=lambda x:x[-1])
new_vals = [[a, list(b)] for a, b in itertools.groupby([_elem(*i) for i in _sort])]
return {tuple(i._k for i in b):a._v for a, b in new_vals}
data = [{0: (0,), 1: (0,), 2: (1,)}, {0: (1,), 1: (0,), 2: (2,)}, {0: (1,0), 1: (0,), 2: (2,)}, {0: (1,), 1: (0,), 2: (1,)}]
print([group_vals(i) for i in data])
输出:
[{(0, 1): (0,), (2,): (1,)},
{(1,): (0,), (0,): (1,), (2,): (2,)},
{(1, 0): (0,), (2,): (2,)},
{(1,): (0,), (0, 2): (1,)}]
递归解决方案:
def group_vals(_d, _start, _seen):
while True:
_options = [i for i in _d if (any(c in _start[-1] for c in i[-1]) or any(c in i[-1] for c in _start[-1])) and i not in _seen]
if _options:
_start = [(*(a for a, _ in _options), *([_start[0]] if isinstance(_start[0], int) else _start[0])), tuple(set([*_start[-1], *[_h for _, b in _options for _h in b]]))]
_seen.extend(_options)
else:
yield _start
break
for i in _d:
if i not in _seen:
yield from group_vals(_d, i, _seen+[i])
data = [{0: (0,), 1: (0,), 2: (1,)}, {0: (1,), 1: (0,), 2: (2,)}, {0: (1,0), 1: (0,), 2: (2,)}, {0: (1,), 1: (0,), 2: (1,)}, {0: (0, 1, 2), 1: (0,), 2: (0,), 3: (0,), 4: (2,)}, {0:(0,1), 1:(1,2), 2: (2,3)}]
new_results = [dict((lambda x:list(group_vals(x[1:], x[0], [])))(list(i.items()))) for i in data]
输出:
[{(1, 0): (0,), 2: (1,)},
{0: (1,), 1: (0,), 2: (2,)},
{(1, 0): (0, 1), 2: (2,)},
{(2, 0): (1,), 1: (0,)},
{(1, 2, 3, 4, 0): (0, 1, 2)},
{(2, 1, 0): (0, 1, 2, 3)}]
答案 1 :(得分:0)
这不是我编写过的最漂亮的代码,但是我认为它可以满足您的要求。
首先,将键和值转换为集合,并将它们组合为(key_set,value_set)元组的列表集合。创建一个空列表rsets。 遍历两个列表中的元组;如果sset和rsets元组的value_sets相交,则用key_sets和value_sets的并集更新rset元组。如果找不到匹配项,则将ssets tuple添加到rsets。最后,将rsets转换为dict。
s1 = {0: (0,), 1: (0,), 2: (1,)}
s2 = {0: (1,), 1: (0,), 2: (2,)}
s3 = {0: (1,0), 1: (0,), 2: (2,)}
for s in (s1, s2, s3):
ssets = [(set([k]),set(v)) for k,v in s.items()]
rsets = []
for (skey_set, svalue_set) in ssets:
for i, (rkey_set, rvalue_set) in enumerate(rsets):
if svalue_set & rvalue_set:
rsets[i] = (skey_set|rkey_set, svalue_set|rvalue_set)
break
else:
rsets.append((skey_set,svalue_set))
r = dict((tuple(k),tuple(v)) if len(k) > 1 else (tuple(k)[0],tuple(v))
for k,v in rsets)
print(r)
输出:
{(0, 1): (0,), 2: (1,)}
{0: (1,), 1: (0,), 2: (2,)}
{(0, 1): (0, 1), 2: (2,)}