2

假设我有以下内容:

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]

生成以下分组的最常见或最有效的算法是什么?

[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 = 鲍勃,米 = 玛丽

2) 生成所有字母的集合:{a, b, c, d, e, f}

3) 遍历子集,对于每个字母,查看字母是否存在于子集的所有元素中

所以...

subset = {j, b, m}

letter = a
    j contains a? true
    b contains a? true
    m contains a? true
        * add a to subset {j, b, m}

letter = b
    j contains b? true
    b contains b? false, continue

letter = c
    j contains c? true
    b contains c? true
    m contains c? false, continue
.....

subset = {j, m}
.....

有更好的解决方案吗?

编辑:上述算法有缺陷。例如,{j, m} 也会包含“a”,这是我不想要的。我想我可以简单地修改它,以便在每次迭代中,我还检查这个字母是否“不在”这个集合中的元素。所以在这种情况下,我还会检查:

if b does not contain a
4

2 回答 2

1

您可以使用两个地图/字典来实现这一点,一个是另一个的“逆”。对于第一个地图,“键”是名称,“值”是字符列表。第二个映射将字母作为键,将与其关联的名称列表作为值。

在 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] 等。您还可以if john does not contain a通过检查 reverseDict['a'] 返回的列表是否包含 john 来检查。

[编辑] 将聚合添加到 finalDict。

您可以使用 freezesets 作为字典键,因此 finalDict 现在包含正确的结果。打印字典:

frozenset({'bob', 'mary'})
['e']

frozenset({'mary'})
['f']

frozenset({'john', 'bob'})
['c', 'd']

frozenset({'john', 'mary'})
['b']

frozenset({'john', 'bob', 'mary'})
['a']
于 2014-11-18T22:50:06.873 回答
0

第 3 步(迭代子集)效率低下,因为它对幂集中的每个元素都执行“j 包含 a”或“a 不在 j 中”。

这是我的建议:

1) 生成幂集 {{j, b, m}, {j, m}, {j, b} {b, m}, {m}, {j}, {b}}。您不需要此步骤,因为您不关心最终输出中的空映射。

2)遍历原始数据结构中的所有元素并构造以下内容:

[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 以填充剩余的空映射。

编辑:Hers 是 Java 中的完整代码

    // The original data structure. mapping from "john" to [a, b, c..] 
    HashMap<String, HashSet<String>> originalMap = new HashMap<String, HashSet<String>>();

    // The final data structure. mapping from power set to [a, b...]
    HashMap<HashSet<String>, HashSet<String>> finalMap = new HashMap<HashSet<String>, HashSet<String>>();

    // Intermediate data structure. Used to hold [a] to [j,b...] mapping
    TreeMap<String, HashSet<String>> tmpMap = new TreeMap<String, HashSet<String>>();

    // Populate the original dataStructure
    originalMap.put("john", new HashSet<String>(Arrays.asList("a", "b", "c", "d")));
    originalMap.put("bob", new HashSet<String>(Arrays.asList("a", "c", "d", "e")));
    originalMap.put("mary", new HashSet<String>(Arrays.asList("a", "b", "e", "f")));

    // Hardcoding the powerset below. You can generate the power set using the algorithm used in googls guava library.
    // powerSet function in https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/collect/Sets.java
    // If you don't care about empty mappings in the finalMap, then you don't even have to create the powerset
    finalMap.put(new HashSet<String>(Arrays.asList("john", "bob", "mary")), new HashSet<String>());
    finalMap.put(new HashSet<String>(Arrays.asList("john", "bob")), new HashSet<String>());
    finalMap.put(new HashSet<String>(Arrays.asList("bob", "mary")), new HashSet<String>());
    finalMap.put(new HashSet<String>(Arrays.asList("john", "mary")), new HashSet<String>());
    finalMap.put(new HashSet<String>(Arrays.asList("john")), new HashSet<String>());
    finalMap.put(new HashSet<String>(Arrays.asList("bob")), new HashSet<String>());
    finalMap.put(new HashSet<String>(Arrays.asList("mary")), new HashSet<String>());

    // Iterate over the original map to prepare the tmpMap.
    for(Entry<String, HashSet<String>> entry : originalMap.entrySet()) {
        for(String value : entry.getValue()) {
            HashSet<String> set = tmpMap.get(value);
            if(set == null) {
                set = new HashSet<String>();
                tmpMap.put(value, set);
            }
            set.add(entry.getKey());
        }
    }

    // Iterate over the tmpMap result and add the values to finalMap
    for(Entry<String, HashSet<String>> entry : tmpMap.entrySet()) {
        finalMap.get(entry.getValue()).add(entry.getKey());
    }

    // Print the output
    for(Entry<HashSet<String>, HashSet<String>> entry : finalMap.entrySet()) {
        System.out.println(entry.getKey() +" : "+entry.getValue());
    }

上面代码的输出将是:

[bob] : []
[john] : []
[bob, mary] : [e]
[bob, john] : [d, c]
[bob, john, mary] : [a]
[mary] : [f]
[john, mary] : [b]
于 2014-11-18T23:03:34.330 回答