我的列表包含[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
的{{1}}个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());
这有效,但可以简化吗?
答案 0 :(得分:10)
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
实例。我只是通过委托Acc
方法将收到的Acc
实例的所有元素添加到此add
实例。
最后,我正在使用Collector.of
基于Acc
类的方法创建一个收集器。最后一个参数是一个修整器函数,它只返回Acc
实例的列表。
答案 1 :(得分:3)
如果你在类路径上有guava
,这是一件轻而易举的事:
block
.stream()
.flatMap(Set::stream)
.collect(Collectors.toCollection(TreeSet::new));
Iterable<List<Integer>> result = Iterables.partition(sorted, 3);
答案 2 :(得分:3)
添加另一个答案,因为这会比评论更大。这真的是接受的答案所做的,但是有一个更聪明的&#34;不需要一直流动的组合器。
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);
}