java流中基于两个条件的数据过滤

wlzqhblo  于 2023-04-28  发布在  Java
关注(0)|答案(4)|浏览(148)

我有以下代码

public class Car {
    Long carNum;
    String carEngine;
}

List对象中的数据如下:

Car(carNum=1, carEngine=S02K), 
Car(carNum=1, carEngine=null), 
Car(carNum=2, carEngine=null),
Car(carNum=2, carEngine=S9K),
Car(carNum=3, carEngine=null)

我如何从汽车对象中筛选出数据
check fordistinct carNum如果有多个相似的carNum,则检查carEngine不为null的位置,并以列表的形式返回数据。
我可以使用不同的carNum

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
}

以如下方式:

carList.stream().filter(distinctByKey(Car::getCarNum)).collect(Collectors.toList());

上面的代码得到了不同的carNum,但是很有可能它会返回带有null carEngine的结果。
我如何检查carEngine不为null的地方沿着不同的carNum组合。

**注意:**如果只有一个不同的carNum没有carEngine,那么我应该返回该行沿着其他行。

例如:如果输入数据看起来像这样:

Car(carNum=1, carEngine=S02K), 
Car(carNum=1, carEngine=null), 
Car(carNum=2, carEngine=null),
Car(carNum=2, carEngine=S9K),
Car(carNum=3, carEngine=null)

则输出应为:

Car(carNum=1, carEngine=S02K), 
Car(carNum=2, carEngine=S9K),
Car(carNum=3, carEngine=null)

请告诉我。谢谢大家!

nbysray5

nbysray51#

我推荐使用带有merge函数的toMap()收集器来选择具有非空引擎的收集器:

carList.stream()
        .collect(Collectors.collectingAndThen(
                Collectors.toMap(
                        Car::getCarNum,
                        c -> c,
                        (a, b) -> a.getCarEngine() != null ? a : b),
                map -> new ArrayList<>(map.values())))

这样,如果有一个carNum只有空引擎,第一个引擎将保持最终结果。

0dxa2lsx

0dxa2lsx2#

predicate 提供了方法and(),它允许您使用逻辑AND合并两个 predicate 。
返回一个复合 predicate ,该 predicate 表示此 predicate 与另一个 predicate 的短路逻辑AND。当计算组合 predicate 时,如果该 predicate 为false,则不计算另一个 predicate 。
示例:

Predicate<Car> distinctByCarNum = distinctByKey(Car::getCarNum);
Predicate<Car> engineNonNull = car -> Objects.nonNull(car.getCarEngine());
Predicate<Car> combinedPredicate = distinctByCarNum.and(engineNonNull);
List<Car> filtered = carList.stream()
    .filter(combinedPredicate)
    .collect(Collectors.toList());

**编辑:**需求更新后,需要分组,不需要过滤。有关正确的解决方案,请参阅answer from shmosel

2nc8po8w

2nc8po8w3#

这里有一个办法。

  • 第一个是carNum
  • 然后对于相同的carNums的每个集合,我首先检查carEngine的所有集合都为空。如果是,我只返回集合中的第一个。
  • 否则,我流列表并选择第一个不为空的列表,因为其中一个必须为空。
List<Car> results = carList.stream().collect(Collectors.groupingBy(Car::getCarNum)).values()
        .stream().map(lst -> {
            if (lst.stream().filter(car -> car.getCarEngine() == null)
                    .count() == lst.size()) {
                return lst.get(0);
            } else {
                return lst.stream()
                        .filter(car -> car.getCarEngine() != null)
                        .findFirst().get();
            }
        }).toList();

印刷品

Car [carNum=1, carEngine=S02K]
Car [carNum=2, carEngine=S9K]
Car [carNum=3, carEngine=null]
laximzn5

laximzn54#

过滤前使用nullsLast排序

技巧是在distinct-filter之前使用nulls last进行排序:

// first by number
Comparator.comparing(Car::getNum)
  // we prefer with engine before no engine.
  .thenComparing(Car::getEngine, Comparator.nullsLast(Comparator.naturalOrder()))

您可以在过滤之前将此比较器传递给Stream.sorted()步骤。

解决方案

import java.util.*
import java.util.Comparator;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.stream.*;

class Car {
  int num;
  String engine;

  public Car(int num, String engine) {
    this.num = num;
    this.engine = engine;
  }

  public Integer getNum() {
    return this.num;
  }

  public String getEngine() {
    return this.engine;
  }

  public String toString() {
    return String.format("Car: %d, %s", num, engine);
  }
}

/* Name of the class has to be "Main" only if the class is public. */
class Ideone {
  public static <T> Predicate<T> distinctByKey(
      Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
  }

  public static Comparator<Car> withNullEnginesLast() {
    return Comparator.comparing(Car::getNum)
        .thenComparing(
            Car::getEngine, Comparator.nullsLast(Comparator.naturalOrder()));
  }

  public static void main(String[] args) throws java.lang.Exception {
    // your code goes here

    var carList = List.of(
        // num, engine
        new Car(1, "S02K"),
        new Car(1, null),  // filter out as duplicate (nulls last)
        new Car(2, null),  // filter out as duplicate (nulls last)
        new Car(2, "S9K"),
        new Car(3, null)  // include because only occurrence for number
    );

    var result =
        carList.stream()
            .sorted(withNullEnginesLast()) // sort first by num, then engine
                                           // where null-engines last
            .filter(distinctByKey(Car::getNum))
            .collect(Collectors.toList());

    System.out.println(result);
  }
}

打印汽车2和发动机

[Car: 1, S02K, Car: 2, S9K, Car: 3, null]

在线试用:IDEone demo

参见

相关问题