简体   繁体   English

从两个列表中过滤具有相同属性的对象并更新它们并将其存储在 Java 8 中的第三个列表中

[英]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 .我有两个列表ab

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.列表ac将是相同的,因为它们将包含相同的引用。 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.

相关问题 从两个列表中过滤对象并减去属性并将其存储在 Java 8 的第三个列表中 - Filter Objects from two lists and do subtract with the attributes and store it in 3rd list in Java 8 Java迭代器和列表-添加到第3个列表 - Java Iterators and Lists - add to 3rd list 两个具有相同引用的java List对象? - Two java List objects having same reference? Java 从其他两个具有不同对象和共同属性的列表构建一个列表 - Java build a list from two other lists with different objects and common property 如何在 java 中组合 2 个具有相同属性值的对象数组列表 - How do I combine 2 array lists of objects having same property value in java Java:两个链接列表中的同一组对象 - Java: the same set of objects in two linked lists Java过滤器列表,它只包含与另一个列表中具有相同属性的对象 - Java filter List that so it only contains objects that have same attribute as in another lists Java-Streams - filter() + map() - Map 来自一个列表的对象缺少属性到另一个列表的对象 - Java-Streams - filter() + map() - Map objects from one List with the missing property to objects from another List 如何连接两个列表以创建第三个列表? - How do I concatenate two lists to create a 3rd? 将两个子类的对象存储在同一个 Vector/List 中 - Store objects of two subclasses in the same Vector/List
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM