【问题标题】:What is the best way to divide a collection into 2 different collections?将一个集合划分为 2 个不同集合的最佳方法是什么?
【发布时间】:2018-07-16 19:46:31
【问题描述】:

我有一组数字:

 Set<Integer> mySet = [ 1,2,3,4,5,6,7,8,9]

我想把它分成两组赔率和偶数。

我的方法是使用两次过滤器:

Set<Integer> set1 = mySet.stream().filter(y -> y % 2 == 0).collect(Collectors.toSet())
Set<Integer> set2 =mySet.stream().filter(y -> y % 2 != 0).collect(Collectors.toSet())

我不喜欢这个解决方案,因为我把整个系列都检查了两次。

有什么更聪明的方法吗?

【问题讨论】:

  • 只需迭代元素,检查它们是偶数还是奇数,然后将它们添加到适当的集合中。一次迭代。
  • 您不想使用经典的 for 循环和 if/else 语句吗?做你的要求很容易......
  • 也许使用 .map 而不是 .filter
  • 在拆分之前对列表进行排序...并查看性能...这样说是因为您已经接受了答案...也试试这个
  • @Pras 性能会更差。排序将元素个数为 O(n) 的算法变成 O(n log n)。

标签: java filter java-8 java-stream data-partitioning


【解决方案1】:
Map<Boolean, List<Integer>> partitioned = 
    set.stream().collect(Collectors.partitioningBy(x -> x%2 == 0));

partitioned.get(true) 中的元素是偶数; partitioned.get(false) 中的元素是奇数。

与使用groupingBy 执行此操作不同,可以保证truefalse 列表都将出现在地图中,即使它们是空的。 (Java 8 中没有记录,但确实如此;Java 9 的文档现在明确说明了这一点)。

【讨论】:

  • 这与 OP 所拥有的本质上不是一样的吗……至少要遍历整个系列两次?不同之处在于 OP 现在有两个不需要再次处理的列表,您的方法将需要在每次有人想要偶数或赔率时处理该列表。
  • @JeffC,据我了解 OP 的问题,OP 关心过滤的两个调用,因为这两个调用都将遍历整个集合。 Andy 的答案只会对集合进行一次迭代,将其分成两组。
  • @conman124 如果我调用partitioned.get(true) 然后partitioned.get(false) 来获取这两个子集,那么集合会被迭代两次,对吧?
  • @JeffC 不,collect 调用会将原始集合拆分为两个列表,一个“真”和一个“假”。真表是偶数元素,假表是奇数元素。调用 partitioned.get(true) 只会返回由 collect 创建的“真实”列表
  • @JeffC conman124 说了什么。地图是常规的HashMap:它不是集合中元素的视图。
【解决方案2】:

您可以使用Collectors#partitioningBy,如下所示。

Map<Boolean,List<Integer>> evenOddMap  = mySet.stream().collect(Collectors.partitioningBy(e -> e % 2 == 0));
System.out.println("Even : "+evenOddMap.get(true));
System.out.println("Odd : "+evenOddMap.get(false));

【讨论】:

    【解决方案3】:

    简单的循环和 if/else 将是一个干净简单的解决方案

    Set<Integer> setEven = new HashSet<>();
    Set<Integer> setOdd = new HashSet<>();
    
    for (Integer val : mySet) {
        if (val % 2 == 0)
            setEven.add(val);
        else
            setOdd.add(val);
    }
    

    或者使用ternary operator 可以更好地简化代码

    for(Integer val : mySet) {
        ((val % 2 == 0) ? setEven : setOdd).add(val);
    }
    

    【讨论】:

    • -1 以这种方式使用条件表达式(但实际上并不是投票):您必须引入一个无意义的变量,因为它不应该像这样使用。只需坚持 if/else。如果您真的想要使用条件表达式,请执行((val%2 == 0) ? setEven : setOdd).add(val);
    • 第二个变体中的boolean b 似乎已过时。您可以忽略未使用的值。
    • @AndyTurner 感谢您的建议,我会做出改变
    【解决方案4】:

    你可以使用Collectors.partitioningBy:

            Map< Boolean, Set<Integer> > map =
            mySet.stream().collect( Collectors.partitioningBy( y -> y % 2 == 0, 
            Collectors.toSet() ) );
    
            Set<Integer> odds = map.get(Boolean.TRUE);
            Set<Integer> evens = map.get(Boolean.FALSE);
    

    编辑:

    我看到有几个类似的答案。这里的细微差别在于它显示了如何将集合作为 Set 而不是 List 以防 OP 想要这样。

    【讨论】:

      【解决方案5】:

      如果你已经有集合来保存值,下面可以是一个解决方案。

      data.stream().forEach(x -> {
      if(x%2==0){
      //add to collection holding even nums
      } else {
      //add to collection holding odd nums
      }
      })
      

      【讨论】:

        【解决方案6】:

        您可以使用groupingBy

        public void test(String[] args) {
            Integer[] test = {1,2,3,4,5,6,7,8,9};
            Map<Integer, List<Integer>> evenOdd = Arrays.stream(test).collect(Collectors.groupingBy(i -> i & 1));
            Set<Integer> evens = new HashSet<>(evenOdd.get(0));
            Set<Integer> odds = new HashSet<>(evenOdd.get(1));
            System.out.println("Evens "+evens+" Odds "+odds);
        }
        

        【讨论】:

        • groupingBy 的缺点是它不能保证“奇数”和“偶数”列表都存在。您可以使用evenOdd.getOrDefault(0, Collections.emptyList());但是使用partitioningBy 会更容易。
        • (不是 DV)您可以在收集的同时使用下游收集器转换为集合:.groupingBy(predicate, Collectors.toSet())
        • @OldCurmudgeon 无法说明为什么投反对票,如果您知道两者都会被填充,或者您可能希望从地图中获取 null(如果它们丢失)。好吧,+1,只是你可以稍微简化一下Map&lt;Boolean, List&lt;Integer&gt;&gt; map = Arrays.stream(test).boxed().collect(Collectors.groupingBy(x -&gt; (x &amp; 1) == 0));
        猜你喜欢
        • 1970-01-01
        • 2019-10-22
        • 1970-01-01
        • 1970-01-01
        • 2017-03-16
        • 2021-10-27
        • 1970-01-01
        • 1970-01-01
        • 2022-09-27
        相关资源
        最近更新 更多