如何使用java8流对TreeSet的列表进行排序
我的列表包含[1,3,5][2,6,4]
等集合,大小相同。 我试过这样做,但似乎没有用。
List<TreeSet> block; for(TreeSet t : block){ block.stream().sorted((n,m)->n.compareTo(m)).collect(Collectors.toSet()); }
我想要的最终结果是[1,2,3][4,5,6]
。
我可以尝试在ArrayList
添加所有元素并对其进行排序,然后创建一个新的TreeSet
List
。 但是有一种衬垫吗?
更新:
List list=new ArrayList(); for(TreeSet t : block){ for(T t1 : t) { list.add(t1); } } list=list.stream().sorted((n,m)->n.compareTo(m)).collect(Collectors.toList());
这有效但可以简化吗?
@ Eugene的答案很甜蜜,因为番石榴很甜。 但如果您的类路径中没有Guava,这是另一种方式:
List> list = block.stream() .flatMap(Set::stream) .sorted() .collect(partitioning(3));
首先,我将所有集合平面化为一个流,然后我将所有元素排序,最后,我将整个排序流收集到集合列表中。 为此,我正在调用一个使用自定义收集器的辅助方法:
private static Collector>> partitioning(int size) { class Acc { int count = 0; List> 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
类的方法创建一个收集器。 最后一个参数是一个修整器函数, Acc
返回Acc
实例的列表。
如果你在类路径上有guava
,这是一件轻而易举的事:
block .stream() .flatMap(Set::stream) .collect(Collectors.toCollection(TreeSet::new)); Iterable> result = Iterables.partition(sorted, 3);
添加另一个答案,因为这将比评论更大。 这确实是接受的答案所做的,但是有一个“更聪明”的组合器,不需要一直流动。
private static Collector>> partitioning(int size) { class Acc { int count = 0; List> 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 lastLeftList = list.get(list.size() - 1); List 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> finisher() { return list.stream().map(LinkedHashSet::new).collect(Collectors.toList()); } } return Collector.of(Acc::new, Acc::add, Acc::merge, Acc::finisher); }
- 如何在Spring中处理DataIntegrityViolationException?
- servlet容器是否应为每个传入请求创建新的javax.servlet.http.HttpServlet实例?
- 为什么我们在连接数据库时使用Class.forName(“oracle.jdbc.driver.OracleDriver”)?
- Spring MVC的问题。 如何从两个或多个对象创建视图?
- 从用户界面接受动态json数据的操作
- Java:如何限制方法对特定类的访问?
- 是否可以使用Guava链接异步调用?
- 性能问题:“java.text.MessageFormat.format”vs“StringBuilder”
- 设置从Eclipse运行的Java程序的内存