java - 当两个元素相同时合并集合

标签 java graph lambda set

这是 compare sets 的后续内容

我有

Set<Set<Node>> NestedSet = new HashSet<Set<Node>>();

[[Node[0], Node[1], Node[2]], [Node[0], Node[2], Node[6]], [Node[3], Node[4], Node[5]]  [Node[2], Node[6], Node[7]] ]

当有两个共同元素时,我想合并集合。例如 0,1,2 和 0,2,6 有两个共同元素,因此将它们合并形成 [0,1,2,6]。

同样,[0,1,2,6] 和 [2,6,7] 有 2 和 6 的共同点。所以合并它们并得到[0,1,2,6,7]。

最终输出应该是:

[  [Node[0], Node[1], Node[2], Node[6], Node[7]], [Node[3], Node[4], Node[5]] ]

我尝试过这样的:

         for (Set<Node> s1 : NestedSet ) {
                        Optional<Set<Node>> findFirst = result.stream().filter(p -> { HashSet<Node> temp = new HashSet<>(s1); 
                        temp.retainAll(p); 
                        return temp.size() == 2; }).findFirst(); 

                        if (findFirst.isPresent()){

                            findFirst.get().addAll(s1); 
                        }
                        else {
                            result.add(s1);
                        }    

                    }

但是我得到的结果是:

[[Node[0], Node[1], Node[2], Node[6], Node[7]], [Node[3], Node[4], Node[5]], [Node[0], Node[2], Node[6], Node[7]]]

有什么想法吗?有什么办法可以得到想要的输出吗?

最佳答案

一些注意事项:

  • 每次应用合并时,都必须重新启动该过程并迭代修改后的集合。因此,输入集的迭代顺序很重要,如果您希望代码具有确定性,您可能需要使用保证其迭代顺序的集合(例如,使用 LinkedHashSet (而不是 HashSet)或列表
  • 您当前的代码有副作用,因为它会在合并时修改提供的集。总的来说,我认为尽可能避免产生副作用是有帮助的。

以下代码可以满足您的要求:

static <T> List<Set<T>> mergeSets(Collection<? extends Set<T>> unmergedSets) {
  final List<Set<T>> mergedSets = new ArrayList<>(unmergedSets);

  List<Integer> mergeCandidate = Collections.emptyList();
  do {
    mergeCandidate = findMergeCandidate(mergedSets);

    // apply the merge
    if (!mergeCandidate.isEmpty()) {
      // gather the sets to merge
      final Set<T> mergedSet = Sets.union(
          mergedSets.get(mergeCandidate.get(0)),
          mergedSets.get(mergeCandidate.get(1)));

      // removes both sets using their index, starts with the highest index
      mergedSets.remove(mergeCandidate.get(0).intValue());
      mergedSets.remove(mergeCandidate.get(1).intValue());

      // add the mergedSet
      mergedSets.add(mergedSet);
    }
  } while (!mergeCandidate.isEmpty());

  return mergedSets;
}

// O(n^2/2)
static <T> List<Integer> findMergeCandidate(List<Set<T>> sets) {
  for (int i = 0; i < sets.size(); i++) {
    for (int j = i + 1; j < sets.size(); j++) {
      if (Sets.intersection(sets.get(i), sets.get(j)).size() == 2) {
        return Arrays.asList(j, i);
      }
    }
  }
  return Collections.emptyList();
}

为了测试此方法,我创建了两个辅助方法:

static Set<Integer> set(int... ints) {
  return new LinkedHashSet<>(Ints.asList(ints));
}

@SafeVarargs
static <T> Set<Set<T>> sets(Set<T>... sets) {
  return new LinkedHashSet<>(Arrays.asList(sets));
}

这些辅助方法允许编写非常可读的测试,例如(使用问题中的数字):

public static void main(String[] args) {
    // prints [[2, 6, 7, 0, 1]]
    System.out.println(mergeSets(sets(set(0, 1, 2, 6), set(2, 6, 7))));
    // prints [[3, 4, 5], [0, 2, 6, 1, 7]]
    System.out.println(
      mergeSets(sets(set(0, 1, 2), set(0, 2, 6), set(3, 4, 5), set(2, 6, 7))));
}

关于java - 当两个元素相同时合并集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34974460/

相关文章:

java - Clojure.java.jdbc 根据查询结构更改日期时间的返回类型

java - 查找 arrayList 中位数的问题

java - 字符串连接,然后在循环中附加

java - 图传递性 Java

python - 如何将绘制的图像居中?

python - 无法使用的函数参数

java - 仅当对象不存在时才将对象添加到 java 结构

c# - 通过 Blazor Server 应用程序调用 Graph 时出现身份验证错误

java - 更改 ConcurrentHashMap 上的现有 foreach 循环以使用 Lambdas 来利用并行处理

c++ - 参数类型模板类型中的通用 lambda auto