流上的 groupingBy
操作是否可以生成一个映射,其中值是数组而不是列表或其他一些集合类型?
例如:我有一个类 Thing
. 事情有所有者,所以 Thing
有一个 getOwnerId
方法 . 在一系列事物中,我想按所有者ID对事物进行分组,以便具有相同所有者ID的事物最终在一个数组中 . 换句话说,我想要一个如下所示的 Map ,其中键是所有者ID,值是属于该所有者的事物的数组 .
Map<String, Thing[]> mapOfArrays;
在我的情况下,因为我需要将映射值传递给需要数组的库方法,所以收集到 Map<String, Thing[]>
最方便 .
将整个流收集到一个数组中很容易(它甚至不需要显式收集器):
Thing[] arrayOfThings = Stream.of(new Thing("owner1"), new Thing("owner2"), new Thing("owner1"))
.toArray(Thing[]::new);
[属于所有者1,属于所有者2,属于所有者1]
所有者ID的摸索也很容易 . 例如,要分组到列表中:
Map<String, List<Thing>> mapOfLists = Stream.of(new Thing("owner1"), new Thing("owner2"), new Thing("owner1"))
.collect(Collectors.groupingBy(Thing::getOwnerId));
{owner1 = [属于所有者1,属于所有者1],所有者2 = [属于所有者2]}
只有这个例子给我一张列表 Map . 有2-arg和3-arg groupingBy
方法可以给我一张其他集合类型的 Map (比如集合) . 我想,如果我可以将收集到一个数组的收集器(类似于上面第一个代码段中的数组中的集合)传递给两个arg Collectors.groupingBy(Function<? super T,? extends K>, Collector<? super T,A,D>)
,我就会被设置 . 但是, Collectors
类中的预定义收集器似乎都没有对数组执行任何操作 . 我错过了一个不太复杂的方式吗?
为了完整的例子,这里是我在上面的片段中使用的类:
public class Thing {
private String ownerId;
public Thing(String ownerId) {
this.ownerId = ownerId;
}
public String getOwnerId() {
return ownerId;
}
@Override
public String toString() {
return "Belongs to " + ownerId;
}
}
3 回答
您可以先分组,然后使用后续的toMap:
可能很明显但你可以通过以下方式完成:
使用this answer by Thomas Pliakas中的收集器:
我们的想法是首先收集到一个列表(这是一个明显的想法,因为数组具有恒定的大小),然后在返回到收集器的分组之前转换为数组 .
collectingAndThen
可以通过它所谓的终结者做到这一点 .要打印结果以供检查:
Edit: 感谢Aomine的链接:使用
new Thing[0]
作为toArray
的参数受到Arrays of Wisdom of the Ancients的启发 . 似乎在Intel CPU上最终使用new Thing[0]
比使用new Thing[tl.size()]
更快 . 我很惊讶 .