在一个流中过滤并设置()

时间:2019-02-06 13:45:28

标签: java collections java-8 java-stream

所以我有一些示例代码正在尝试找出下面的逻辑。它只是一个主要的主要方法和两个POJO,但是它将运行。我正在调试以在终止点获取值。

public class Main {

    public static void main(String[] args) {

        obj1 obj1 = new obj1();
        obj1 obj12 = new obj1();

        obj2 obj2 = new obj2();
        obj2 obj22 = new obj2();

        obj1.id = 123L;
        obj1.carId = 1234L;
        obj12.id = 123L;
        obj12.carId = 1234L;

        obj2.carId = 1234L;
        obj22.carId = 12345L;

        ArrayList<obj1> obj1Arr = new ArrayList<>();
        ArrayList<obj2> obj2Arr = new ArrayList<>();

        obj1Arr.add(obj1);
        obj1Arr.add(obj12);

        obj2Arr.add(obj2);
        obj2Arr.add(obj22);

        List<obj2> newCarList= obj2Arr.stream()
                .filter(anObjOf2 -> obj1Arr
                        .stream()
                        .anyMatch(carReg -> carReg.getCarId().equals(anObjOf2.getCarId())))
                .collect(Collectors.toList());
    }
}

POJO1:

public class obj1 {

    Long id = null;
    Long carId = null;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCarId() {
        return carId;
    }

    public void setCarId(Long carId) {
        this.carId = carId;
    }
}

POJO2:

public class obj2 {

    Long id = null;
    Long carId = null;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCarId() {
        return carId;
    }

    public void setCarId(Long carId) {
        this.carId = carId;
    }
}

如您所见,我正在流式传输并过滤掉obj上不匹配的所有carId。我的下一个目标是在匹配的对象上set id(不是carId)。

基本上,如果obj1.carId == obj2.carId然后是set obj1.id = obj2.id

我的问题是我不知道如何在同一流中执行此操作。可能吗?我忍不住想,此时需要迭代器吗?

4 个答案:

答案 0 :(得分:3)

请勿在一个流中执行这两个操作。这是一个非常糟糕的风格。

首先收集数据。然后突变元素。像这样:

Map<obj2, Optional<obj1>> map = 
    obj2Arr.stream()
           .collect(toMap(identity(), o2 -> obj1Arr.stream()
                                                  .filter(o1 -> o1.getCarId().equals(o2.getCarId()))
                                                  .findAny()));

map.forEach((o1, optO2) -> optO2.ifPresent(o2 -> o1.setId(o2.id)));

否则,您可以只使用嵌套的for-each循环。

答案 1 :(得分:2)

我建议首先为第一个列表中的每个元素创建一个MapcarId的映射(我对您的类做了一些修改,以使其更易读和删除。重复的ID,我认为这是一个错误):

id

然后,您可以使用此@Data @AllArgsConstructor class Car { Long id = null; Long carId = null; } List<Car> obj1Arr = Arrays.asList(new Car(1L, 123L), new Car(2L, 1234L)); List<Car> obj2Arr = Arrays.asList(new Car(0L, 1234L), new Car(0L, 12345L)); Map<Long, Long> carIdToId = obj1Arr.stream() .collect(Collectors.toMap(Car::getCarId, Car::getId)); // [Car(id=2, carId=1234), Car(id=0, carId=12345)] 来过滤具有相同Map的汽车,而不必与其他汽车进行比较。然后,使用carID仅在原始列表中设置ID。

forEach

如果只想让{em {em} 等于obj2Arr.stream() .filter(anObjOf2 -> carIdToId.containsKey(anObjOf2.getCarId())) .forEach(anObjOf2 -> anObjOf2.setId(carIdToId.get(anObjOf2.getCarId()))); System.out.println(obj2Arr); // [Car(id=2, carId=1234), Car(id=0, carId=12345)] ,则可以在carIdpeek中设置ID。不过,这仍然会修改原始实例:

collect

或创建一个全新实例的列表:

obj2Arr = obj2Arr.stream()
        .filter(anObjOf2 -> carIdToId.containsKey(anObjOf2.getCarId()))
        .peek(anObjOf2 -> anObjOf2.setId(carIdToId.get(anObjOf2.getCarId())))
        .collect(Collectors.toList());
System.out.println(obj2Arr);
// [Car(id=2, carId=1234)]

答案 2 :(得分:1)

您可以在谓词anyMatch

中进行操作
List<obj2> newCarList= obj2Arr.stream()
            .filter(anObjOf2 -> obj1Arr
                    .stream()
                    .anyMatch(carReg ->  {
            if(carReg.getCarId().equals(anObjOf2.getCarId()))) {
                 carReg.setId(anObjOf2.getId());
                  return true;
               }
           return false;
     }).collect(Collectors.toList());

第二种方法

先过滤

List<obj2> newCarList= obj2Arr.stream()
            .filter(anObjOf2 -> obj1Arr
                    .stream()
                    .anyMatch(carReg -> carReg.getCarId().equals(anObjOf2.getCarId())))
            .collect(Collectors.toList());

现在设置ID

newCarList.forEach(obj->{
           obj1Arr.forEach(o-> {
            if(o.getCarId().equals(obj.getCarId()) {
                  o.setId(obj.getId());
                }
           };
    });

答案 3 :(得分:1)

如果 O(m*n) 解决方案适合您,那么更简单的实现将使用for循环,如下所示:

// classes renamed for naming convention and relatiing to question at the same time 
List<ObjectTwo> newCarList = new ArrayList<>();
for(ObjectTwo objectTwo: objectTwoArr) {
    for (ObjectOne objectOne : objectOneArr) {
        if (objectTwo.getCarId().equals(objectOne.getCarId())) {
            objectOne.setId(objectTwo.getId());
            newCarList.add(objectTwo);
        }
    }
}

mn是列表的大小。