Algorithm 将项目分组为子集(幂集)
假设我有以下几点:Algorithm 将项目分组为子集(幂集),algorithm,combinations,powerset,Algorithm,Combinations,Powerset,假设我有以下几点: john: [a, b, c, d] bob: [a, c, d, e] mary: [a, b, e, f] [a] : [j, b, m] [b] : [j, m] [c] : [j, b] [d] : [j, b] [e] : [b, m] [f] : [m] 或者稍微重新格式化,以便您可以轻松查看分组: john: [a, b, c, d] bob: [a, c, d, e] mary: [a, b, e, f] 生成以下分组的最常见或最有
john: [a, b, c, d]
bob: [a, c, d, e]
mary: [a, b, e, f]
[a] : [j, b, m]
[b] : [j, m]
[c] : [j, b]
[d] : [j, b]
[e] : [b, m]
[f] : [m]
或者稍微重新格式化,以便您可以轻松查看分组:
john: [a, b, c, d]
bob: [a, c, d, e]
mary: [a, b, e, f]
生成以下分组的最常见或最有效的算法是什么
[john, bob, mary]: [a]
[john, mary]: [b]
[john, bob]: [c,d]
[bob, mary]: [e]
[mary]: [f]
[john]: []
[bob]: []
快速谷歌搜索后,上面的键似乎代表了“电源组”。因此,我计划进行以下impl:
1) 生成幂集{{j,b,m},{j,m},{j,b}{b,m},{m},{j},{b}//j=john,b=bob,m=mary
2) 生成所有字母的集合:{a,b,c,d,e,f}
3) 迭代子集,对于每个字母,查看该子集的所有元素中是否存在字母
所以
有更好的解决办法吗
编辑:上述算法存在缺陷。例如,{j,m}还将包含我不想要的“a”。我想我可以简单地修改它,以便在每次迭代中,我也检查这个字母是否“不在”不在这个集合中的元素中。所以在这种情况下,我还要检查:
if b does not contain a
您可以使用两个地图/字典来实现这一点,其中一个是另一个的“反向”。对于第一个映射,“key”是名称,“value”是字符列表。第二个映射将字母作为键,并将与之关联的名称列表作为值 用Python
nameDict = {'john' : ['a', 'b', 'c', 'd'], 'bob' : ['a', 'c', 'd', 'e'], 'mary' : ['a', 'b', 'e', 'f']}
reverseDict = {}
for key,values in nameDict.items():
for v in values:
if v in reverseDict.keys():
reverseDict[v].append(key)
else:
reverseDict[v] = [key] # If adding v to dictionary for the first time it needs to be as a list element
# Aggregation
finalDict = {}
for key,values in reverseDict.items():
v = frozenset(values)
if v in finalDict.keys():
finalDict[v].append(key)
else:
finalDict[v] = [key]
这里,reverseDict包含您想要的与a->[john,bob,mary],b->[john,mary]等的映射。您还可以通过检查reverseDict['a']返回的列表是否包含john来检查john是否不包含a
[编辑]将聚合添加到FinalAct中
您可以将frozensets用作字典键,这样finalDict现在就包含正确的结果。打印词典:
frozenset({'bob', 'mary'})
['e']
frozenset({'mary'})
['f']
frozenset({'john', 'bob'})
['c', 'd']
frozenset({'john', 'mary'})
['b']
frozenset({'john', 'bob', 'mary'})
['a']
步骤3(在子集上迭代)将是低效的,因为它会对幂集中的每个元素执行“j包含a”或“a不在j中”
以下是我的建议:
1) 生成幂集{{j,b,m},{j,m},{j,b}{b,m},{m},{j},{b}。您不需要这个步骤,因为您不关心最终输出中的空映射
2) 迭代原始数据结构中的所有元素,并构造以下内容:
john: [a, b, c, d]
bob: [a, c, d, e]
mary: [a, b, e, f]
[a] : [j, b, m]
[b] : [j, m]
[c] : [j, b]
[d] : [j, b]
[e] : [b, m]
[f] : [m]
3) 颠倒上述结构和聚合(使用[j,b,…]的映射到[a,b,…]的列表应该可以做到这一点)得到:
[j, b, m] : [a]
[j, m] : [b]
[j, b] : [c, d]
[b, m] : [e]
[m] : [f]
4) 将3与1进行比较以填充剩余的空映射
编辑:
这是Java中的完整代码
谢谢,我相信我的困惑是聚合步骤。我不确定是否使用集合作为地图的键。这有什么问题吗?我相信我可以使用guava和apache commons中的多键映射,但我最初计划在JS浏览器中这样做。@nogridbag设置为映射的键是可以的,只要在将其作为键添加到映射后该集不会更改。我认为在多键贴图中,键的顺序很重要。如果键的顺序很重要,那么您可能必须在生成键之前进行排序。谢谢,这很接近,但缺少聚合步骤。例如,您的代码将输出c->{b,j}和d->{b,j},而我需要{b,j}->[c,d]@nogridbag。我认为聚合可以通过制作另一个反向映射来完成,这次是反向指令。这样,键{b,j}将具有相应的值[c,d]。Tim,现在还早,我还没有喝咖啡,但我相信你的聚合步骤只会返回原始数据集:nameDict:)@nogridbag,这会教我不要测试我的答案!我已经使用Frozenset更新了我的答案,现在它产生了正确的结果。
[bob] : []
[john] : []
[bob, mary] : [e]
[bob, john] : [d, c]
[bob, john, mary] : [a]
[mary] : [f]
[john, mary] : [b]