【问题标题】:How do I sort a List of TreeSets with java8 streams如何使用 java8 流对 TreeSet 列表进行排序
【发布时间】:2017-06-02 21:14:44
【问题描述】:

我的列表包含 [1,3,5][2,6,4] 等集合,大小相同。 我试过这样做,但它似乎不起作用。

List<TreeSet<T>> block;
    for(TreeSet<T> t : block){
        block.stream().sorted((n,m)->n.compareTo(m)).collect(Collectors.toSet());

    }

我想要的最终结果是[1,2,3][4,5,6]

我可以尝试在ArrayList 中添加所有元素并对其进行排序,然后创建一个新的List TreeSet。但是有没有某种单线?

更新:

List<T> list=new ArrayList<T>();
    for(TreeSet<T> t : block){

        for(T t1 : t)
        {
            list.add(t1);   

        }
    }

    list=list.stream().sorted((n,m)->n.compareTo(m)).collect(Collectors.toList());

这可行,但可以简化吗?

【问题讨论】:

  • 只是为了确定 - 您想重新排列元素,使每个集合包含三个元素,并且集合本身按升序排列?
  • 确保有一个衬里,如果你从左边开始,并将你的边距设置在右边。而且一旦写出来,就没有人能够阅读了。
  • 是的,这就是我想要的最终结果@Mureinik
  • 该代码不起作用,因为您正在将集合与集合进行比较。然而,很明显这些集合基本上是不相关的——看起来你需要展平,然后对 that 进行排序。
  • @LexByte 你需要flatMap 然后排序再收集。 block.stream().flatMap(Set::stream).sorted().collect(Collectors.toList())。请注意,(n,m)-&gt;n.compareTo(m) 根本不需要。

标签: java java-8 java-stream treeset


【解决方案1】:

@Eugene 的回答很甜,因为番石榴很甜。但如果你的类路径中碰巧没有 Guava,这里有另一种方法:

List<Set<Integer>> list = block.stream()
    .flatMap(Set::stream)
    .sorted()
    .collect(partitioning(3));

首先,我将所有集合平面映射到一个流中,然后对所有元素进行排序,最后,我将整个排序的流收集到集合列表中。为此,我正在调用一个使用自定义收集器的辅助方法:

private static <T> Collector<T, ?, List<Set<T>>> partitioning(int size) {
    class Acc {
        int count = 0;
        List<Set<T>> list = new ArrayList<>();

        void add(T elem) {
            int index = count++ / size;
            if (index == list.size()) list.add(new LinkedHashSet<>());
            list.get(index).add(elem);
        }

        Acc merge(Acc another) {
            another.list.stream().flatMap(Set::stream).forEach(this::add);
            return this;
        }
    }
    return Collector.of(Acc::new, Acc::add, Acc::merge, acc -> acc.list);
}

该方法接收每个分区的大小并使用Acc本地类作为收集器使用的可变结构。在Acc 类中,我使用了一个List,它将包含LinkedHashSet 实例,它将保存流的元素。

Acc 类保存已收集的所有元素的计数。在add 方法中,我计算列表的索引并增加此计数,如果列表的该位置没有设置,我将添加一个新的空LinkedHashSet 到它。然后,我将元素添加到集合中。

当我在流上调用sorted() 以在收集之前对其元素进行排序时,我需要使用保留插入顺序的数据结构。这就是为什么我将ArrayList 用于外部列表,将LinkedHashSet 用于内部集合。

merge 方法将由并行流使用,以合并两个先前累积的 Acc 实例。我只是通过委托给add 方法,将接收到的Acc 实例的所有元素添加到这个Acc 实例中。

最后,我使用Collector.of 根据Acc 类的方法创建一个收集器。最后一个参数是一个finisher函数,它只返回Acc实例的列表。

【讨论】:

  • 经过深思熟虑和解释清楚。
  • 喜欢在方法中定义的单一用途类。次要 nitpick:它无法编译,因为 count++/sizelongcount 应该是 int,或者如果保留为 long,则 index 应该使用 Math.toIntExact(count++ / size) 计算(尽管我不确定支持我们需要的如此大的列表是否有用排序)。
  • 感谢@Federico 的快速编辑。我发现很难为自定义需求实现Collector,这是一个非常好的和鼓舞人心的例子。
  • @Eugene 我猜他想将排序顺序保持为迭代顺序
  • @FedericoPeraltaSchaffner 我添加了另一个答案,以表明组合器可以大大简化......
【解决方案2】:

如果您在类路径中有guava,这很容易:

        block
            .stream()
            .flatMap(Set::stream)
            .collect(Collectors.toCollection(TreeSet::new));

    Iterable<List<Integer>> result = Iterables.partition(sorted, 3);

【讨论】:

    【解决方案3】:

    添加另一个答案,因为这比评论更大。这确实是公认的答案所做的,但使用了一个“更智能”的组合器,不必再次流式传输。

     private static <T> Collector<T, ?, List<Set<T>>> partitioning(int size) {
        class Acc {
            int count = 0;
    
            List<List<T>> list = new ArrayList<>();
    
            void add(T elem) {
                int index = count++ / size;
                if (index == list.size()) {
                    list.add(new ArrayList<>());
                }
                list.get(index).add(elem);
            }
    
            Acc merge(Acc right) {
    
                List<T> lastLeftList = list.get(list.size() - 1);
                List<T> firstRightList = right.list.get(0);
                int lastLeftSize = lastLeftList.size();
                int firstRightSize = firstRightList.size();
    
                // they have both the same size, simply addAll will work
                if (lastLeftSize + firstRightSize == 2 * size) {
                    System.out.println("Perfect!");
                    list.addAll(right.list);
                    return this;
                }
    
                // last and first from each chunk are merged "perfectly"
                if (lastLeftSize + firstRightSize == size) {
                    System.out.println("Almost perfect");
                    int x = 0;
                    while (x < firstRightSize) {
                        lastLeftList.add(firstRightList.remove(x));
                        --firstRightSize;
                    }
                    right.list.remove(0);
                    list.addAll(right.list);
                    return this;
                }
    
                right.list.stream().flatMap(List::stream).forEach(this::add);
                return this;
            }
    
            public List<Set<T>> finisher() {
                return list.stream().map(LinkedHashSet::new).collect(Collectors.toList());
            }
    
        }
        return Collector.of(Acc::new, Acc::add, Acc::merge, Acc::finisher);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-07
      • 2017-10-05
      • 1970-01-01
      • 2018-11-11
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-10
      相关资源
      最近更新 更多