gpt4 book ai didi

java - 使用 Java Stream 条件映射到新对象

转载 作者:行者123 更新时间:2023-11-29 03:07:09 26 4
gpt4 key购买 nike

我有一个对象流(一个列表),我想从该流中创建新对象,并将其插入到一个集合中。但是,传入列表中的两个或多个对象可能散列到集合中的同一个键,在这种情况下,我想将第 n 个列表对象中的字符串附加到集合中已有的对象,而不是创建一个新对象。

像这样,但以函数形式:

HashSet<ClassB> mySet = new HashSet<>();
for (ClassA instanceA : classAList) {
if (mySet.contains(ClassB.key(instanceA))) { //static method call to find the key
mySet.get(instanceA).appendFieldA(instanceA.getFieldA());
} else {
mySet.add(new ClassB(instanceA));
}
}
return mySet;

在函数形式中,我想创建这样的东西:

List classAList = new ArrayList<>();
classAList.stream()
.map(instanceA -> new ClassB(instanceA))
.collect(Collectors.toSet());

但是当然这会忽略散列图,并且我不会将我的多个 ClassA 实例的字段组合起来,这些实例都将解析为同一个 ClassB。我不确定如何把它放在那里。我是否需要忽略 map() 调用并创建自定义收集器来完成这项工作?似乎有不止一种方法可以做到这一点,但我是 Streams 的新手。

最佳答案

很难理解您真正想要的是什么,因为您的代码示例根本不起作用。问题是 Set 不像 Map 那样工作,你不能向它请求包含的等效对象。除此之外,您还为 contains(…)get(…) 调用使用了不同的对象。此外,还不清楚 ClassB.key(instanceA)new ClassB(instanceA) 之间的区别是什么。

让我们尝试重新定义它:

假设我们有一个键类型 Key 和一个方法 Key.key(instanceA) 来定义候选组。然后我们有一个 ClassB,它是通过 new ClassB(instanceA) 为单个(或主 ClassA 实例)创建的结果类型,具有.appendFieldA(...) 方法在合并两个组成员时接收另一个 ClassA 实例的值。然后,原始(Java 8 之前的)代码将如下所示:

HashMap<Key, ClassB> myMap = new HashMap<>();
for(ClassA instanceA: classAList) {
Key key=Key.key(instanceA);
if(myMap.containsKey(key)) {
myMap.get(key).appendFieldA(instanceA.getFieldA());
} else {
myMap.put(key, new ClassB(instanceA));
}
}

然后,myMap.values() 为您提供了 ClassB 实例的集合。如果它必须是一个 Set,您可以通过以下方式创建它

Set<ClassB> result=new HashSet<>(myMap.values());

请注意,当 KeyClassB 在您的代码中看起来完全相同时,这也有效,但您可能会问自己,是否真的需要两者,通过 .key(instanceA) 创建的实例和通过 new ClassB(instanceA) 创建的实例......


这可以通过 Java 8 API 简化为:

for(ClassA instanceA: classAList) {
myMap.compute(Key.key(instanceA), (k,b)-> {
if(b==null) b=new ClassB(instanceA);
else b.appendFieldA(instanceA.getFieldA());
return b;
});
}

或者,如果你想让它看起来更实用:

classAList.forEach(instanceA ->
myMap.compute(Key.key(instanceA), (k,b)-> {
if(b==null) b=new ClassB(instanceA);
else b.appendFieldA(instanceA.getFieldA());
return b;
})
);

对于流解决方案,存在一个问题,合并函数将获得相同类型的两个实例,此处为 ClassB,并且无法访问 ClassA通过周围的上下文实例,就像我们对上面的 compute 解决方案所做的那样。对于流解决方案,我们需要 ClassB 中的一个方法,它返回我们传递给其构造函数的第一个 ClassA 实例,比如 getFirstInstanceA() .然后我们可以使用:

Map<Key, ClassB> myMap = classAList.stream()
.collect(Collectors.toMap(Key::key, ClassB::new, (b1,b2)->{
b1.appendFieldA(b2.getFirstInstanceA().getFieldA());
return b1;
}));

关于java - 使用 Java Stream 条件映射到新对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31575621/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com