【问题标题】:Iterate over all unique two-element combinations迭代所有独特的二元素组合
【发布时间】:2014-05-09 10:27:04
【问题描述】:

我需要遍历两个元素的所有组合:在一个集合 [1,2,3,4] 我想遍历 [(1,2),(1,3),(1,4), (2,3),(2,4),(3,4)]。是否有现成的工具可以这样做?

// Not what I need, works wrong!
for (Object o1 : set) {
  for (Object o2 : set) {
    if (o1 == o2) continue;
    ...
  }
}

此代码将执行比所需操作多两倍的操作,因为每个对象都将在两个循环中被访问。

为此编写自己的方法是微不足道的,我只是不想发明轮子。我希望在 Guava 或 Collections API 中找到它,但没有找到这样的功能。

【问题讨论】:

  • 首先,您应该使用o1.equals(o2) 而不是o1 == o2,除非您实际使用的是原语。
  • @Cedric_Reichenbach 不。那是一个集合,不可能有两个彼此相等的元素。 == 在这里就足够了。
  • 您总是需要遍历这两个集合以找到这些组合。即使你得到另一个 api 内部逻辑也会有同样的复杂性。
  • @Susei 它可能会导致人们得到错误的答案,因为您发布的代码的正确输出是(1, 2) (1, 3) (1, 4) (2, 1) (2, 3) (2, 4) (3, 1) (3, 2) (3, 4) (4, 1) (4, 2) (4, 3)。基本上这个问题有不一致的地方。
  • @Math 是的,这就是为什么在下一句中我解释了为什么该代码不适合我的任务。

标签: java guava


【解决方案1】:

https://code.google.com/p/combinatoricslib/ 简单组合部分说明了此实用程序的用法。 结合 2 个元素将产生您想要的结果。

    // Create the initial vector
    ICombinatoricsVector<String> initialVector = Factory.createVector(
      new String[] { "red", "black", "white", "green", "blue" } );

   // Create a simple combination generator to generate 3-combinations of the initial vector
   Generator<String> gen = Factory.createSimpleCombinationGenerator(initialVector, 3);

   // Print all possible combinations
   for (ICombinatoricsVector<String> combination : gen) {
      System.out.println(combination);
   }

【讨论】:

    【解决方案2】:

    break 替换continue 几乎可以满足您的要求:它不会产生交换对。它还将开销减半(您不关心)。

    您只需交换 o1o2 的名称即可获得所需的确切配对。


    正如评论中所指出的,Sets 没有迭代顺序保证。所以可以肯定的是,事先将Set 转换为List。对于大型套装,这比配对本身便宜得多(O(n) vs O(n*n))。

    【讨论】:

    • 一个非常好的解决方案!虽然我不确定任何现有的 Set 实现是否会在这两个循环中以相同的顺序迭代(这是它工作的必要条件),但仍然。
    • @Susei:我见过的所有可迭代对象都以固定的顺序进行迭代。它可以在实现之间改变(这肯定发生在 JDK9 HashSet 中),但实现者努力不这样做。但你是对的,没有这样的保证。
    【解决方案3】:

    我不确定您要使用什么 Set,但如果它具有随机访问权限,也就是说,如果您可以明确要求位置为 i 的成员,那么您可以使用双 for 和第二个迭代器逐渐增加: 例如

    for(i = 0; i < Set1_size; i++)
     for(j = i; j < Set1_size; i++)
    { o1.get(i).equals(o2); }
    

    这样你只循环了~一半(实际上是一半+你的主对角线)之前的比较。

    【讨论】:

    • 使用set.size()。而且只有一套,不是两套。 j++你的意思是第二个for,对吧?
    • 你把Set和Collection搞混了。根据定义,Set 没有随机访问。你在谈论一个列表。但是逻辑很好,我可以将 Set 转换为 ad-hoc List 并对其进行循环。尽管我仍然会寻找具有有意义名称的现有工具,而不是编写循环。喜欢Iterable&lt;Pair&lt;Object, Object&gt;&gt; Sets.allCombinationsOf(set, 2)
    • 通过您的实现,您需要先将集合转换为数组,因为没有 get 这样的东西。
    • @ArtjomB。是的,这就是我所说的“将集合转换为临时列表”的意思。
    • 是的,在第二个 for 循环中应该是 j++
    猜你喜欢
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2023-02-22
    • 2013-05-28
    • 1970-01-01
    相关资源
    最近更新 更多