[英]Filter Objects having the same property from two Lists and Update them and Store it in a 3rd List in Java 8
I have the following class:我有以下 class:
@AllArgsConstructor
@Getter
@Setter
public static class Manipulate {
private int id;
private int quantity;
}
And I have two lists a
and b
.我有两个列表
a
和b
。
List<Manipulate> a = new ArrayList<>();
a.add(new Manipulate(1,100));
a.add(new Manipulate(2,200));
List<Manipulate> b = new ArrayList<>();
b.add(new Manipulate(1,10));
b.add(new Manipulate(2,20));
I need to filter these two lists based on the id
property.我需要根据
id
属性过滤这两个列表。
And I want to subtract quantities of objects contained in b
from quantities of objects contained in a
and store the result into a List
.我想从 a 中包含的对象数量中减去
b
中包含a
对象数量,并将结果存储到List
中。
My attempt:我的尝试:
List<Manipulate> c = a.stream().map(k -> {
b.stream().filter(j -> j.getId() == k.getId())
.forEach(i -> {
int i1 = k.getQuantity() - i.getQuantity();
k.setQuantity(i1);
});
return k;
});
I'm getting the following compilation error:我收到以下编译错误:
Required type: List <Manipulate> Provided: Stream<Object>
no instance(s) of type variable(s) R exist so that Stream<R> conforms to List<Manipulate>
There are several issues with your code:您的代码有几个问题:
map()
is an intermediate operation , it means that it doesn't produce the resulting value but returns another stream. map()
是一个中间操作,这意味着它不会产生结果值,而是返回另一个 stream。 In order to produce a result from the stream you need to apply a terminal operation (eg collect()
, reduce()
, findFirst()
).为了从 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 产生结果,您需要应用终端操作(例如
collect()
、 reduce()
、 findFirst()
)。 For more information, refer to the API documentation .有关详细信息,请参阅API 文档。
In Functional programming , it's not a good practice to mutate arguments passed to a function (and that's what you're doing inside the map()
).在函数式编程中,对传递给function的 arguments 进行变异并不是一个好习惯(这就是您在
map()
中所做的事情)。
Your code is based on a brute-force logic (which always imply the worst possible performance): for every element in a
iterate over the all elements in b
.您的代码基于蛮力逻辑(这总是暗示可能的最差性能):对于
a
中的每个元素,迭代b
中的所有元素。 Instead, we can index all the id
that are present in the list b
by placing them into a hash-based collection (that would allow to find out whether a particular id
is present in the b
in constant time) and associate each id
with the corresponding quantity
.相反,我们可以通过将列表
b
中存在的所有id
放入基于哈希的集合中来索引它们(这将允许在恒定时间内找出特定id
是否存在于b
中)并将每个id
与对应quantity
。 Ie we can generate HashMap
, that maps each id
in the b
to it's quantity
.即我们可以生成
HashMap
,将b
中的每个id
映射到它的quantity
。
Lists a
and c
would be identical because they would contain the same references.列表
a
和c
将是相同的,因为它们将包含相同的引用。 That means there's no point in generating the list c
unless you want it to contain only elements having id
that are present in the list b
.这意味着生成列表
c
是没有意义的,除非您希望它仅包含具有列表b
中存在的id
的元素。
That's how your code might be reimplemented:这就是您的代码可能被重新实现的方式:
List<Manipulate> a = // initializing list a
List<Manipulate> b = // initializing list b
// mapping each `id` in the `b` to it's `quantity`
Map<Integer, Integer> quantityById = b.stream()
.collect(Collectors.toMap(
Manipulate::getId, // keyMapper
Manipulate::getQuantity // valueMapper
));
// generating the list `c`, containing only elements
// with `id` that are present in the `b`
List<Manipulate> c = a.stream()
.filter(m -> quantityById.containsKey(m.getId()))
.collect(Collectors.toList()); // or .toList() for Java 16+
// updating `quantity` property of each element in `c`
for (Manipulate m : c)
m.setQuantity(
m.getQuantity() - quantityById.get(m.getId())
);
In case if you had no intention to change the data in a
, then you need to create new instances of Manipulate
for every matching id
.如果您不打算更改
a
中的数据,那么您需要为每个匹配的id
创建新的Manipulate
实例。 And it's perfectly fine to do in the stream:在 stream 中做这件事完全没问题:
List<Manipulate> a = // initializing list a
List<Manipulate> b = // initializing list b
Map<Integer, Integer> quantityById = // generate a map like shown above
List<Manipulate> c = a.stream()
.filter(m -> quantityById.containsKey(m.getId()))
.map(m -> new Manipulate(m.getId(), m.getQuantity() - quantityById.get(m.getId())))
.collect(Collectors.toList()); // or .toList() for Java 16+
Note: you need to add the third argument to Collectors.toMap()
in case if there could be duplicated id
in the list b
.注意:您需要将第三个参数添加到
Collectors.toMap()
以防列表b
中可能存在重复的id
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.