Java 流:根据列表 2 中存在的对象过滤列表 1

Java Stream: Filter list 1 based on the objects present in list 2

我正在尝试根据另一个列表中存在的值来过滤一个列表。我已经经历了其他类似的问题,并试图用它来实现我 objective 但我无法这样做。

列表 1 包含 class CarModel(L1)

的对象
public class CarModel   {
  private String year;

  private String model;

}

列表 2 包含 class CarData(L2)

的对象
public class CarData   {
  private OffsetDateTime date;

  private List<CarDetails> carDetails;

}


public class CarDetails   {
  private String owner;

  private List<Cars> cars = null;
}


public class Car   {
  private String modelName;

  private String dealership;

}

我想要实现的是基于 list1Car.modelNamelist2CarModel.model 相匹配的过滤器 list2

例如:

列表 1 包含 3 个对象:

carModel1 = { year: 2019, model: BMW-500-7S-150-Z100 }
carModel2 = { year: 2019, model: MERCEDES-700-7S-350-Z100 }
carModel3 = { year: 2018, model: AUDI-100-Q6-350-Z100 }

列表 2 包含以下对象:

CarData = {
   date: 2-6-2021,
   carDetails: [
   {
     owner: John,
     cars: [ {
          modelName: BMW-500-7S-*-Z100, 
          dealership: Nevada
       },
       {
          modelName:MERCEDES-700-7S-*-Z100, 
          dealership: Daytona
       }
    ]
   }
  ]
}

因此 post 过滤,列表 1 将不包含 c3,因为该模型与 CarData 中的 modelName 不匹配。

我该怎么做?

首先,将模型名称存储为正则表达式或处理它以将其用作正则表达式会更容易(例如,BMW-500-7S-(.*)-Z100 而不是 BMW-500-7S-*-Z100

假设我们像这样使用正则表达式,我们可以使用流来迭代所有 modelNames 并过滤不在 carData 中的 carModels :

List<String> modelNames = carData.getCarDetails().stream()
                                                 .flatMap(e -> e.getCars().stream())
                                                 .map(Car::getModelName)
                                                 .collect(Collectors.toList());
    
List<CarModel> result = carModels.stream()
                                 .filter(carModel ->                                  
                                             modelNames.stream()
                                                       .anyMatch(name -> name.matches(carModel.getModel()))
                                 ).collect(Collectors.toList());

您可以先将嵌套列表展平,然后从列表中提取车型名称作为 HashSet。 :

Set<String> names = carDataList.stream()
      .flatMap(cd -> cd.getCarDetails().stream())
      .flatMap(det -> det.getCars().stream())
      .map(Car::getModelName())
      .collect(Collectors.toCollection(HashSet::new));

您现在可以使用此集合的 contains() 方法来过滤您的 List<CarModel>:

models.stream()
     .filter(model -> names.contains(model.getModel()))
     .collect(Collectors.toList())
     .forEach(m -> System.out.println(m.getModel()));

如果您只想要列表中的名字:

models.stream()
    .map(CarModel::getModel)
    .filter(names::contains)
    .collect(Collectors.toList())
    .forEach(System.out::println);

试试这个。

List<CarModel> list1 = List.of(
    new CarModel("2019", "BMW-500-7S-150-Z100"),
    new CarModel("2019", "MERCEDES-700-7S-350-Z100"),
    new CarModel("2018", "AUDI-100-Q6-350-Z100"));

List<CarData> list2 = List.of(
    new CarData(OffsetDateTime.of(LocalDate.of(2021, 2, 6), LocalTime.of(0, 0), ZoneOffset.UTC),
        List.of(new CarDetails("John", List.of(
            new Car("BMW-500-7S-*-Z100", "Nevada"),
            new Car("MERCEDES-700-7S-*-Z100", "Daytona"))))));

Pattern models = Pattern.compile(list2.stream()
    .flatMap(d -> d.getCarDetails().stream())
    .flatMap(d -> d.getCars().stream())
    .map(c -> c.getModelName().replaceAll("\*", ".*"))
    .collect(Collectors.joining("|")));

List<CarModel> result = list1.stream()
    .filter(m -> models.matcher(m.getModel()).matches())
    .collect(Collectors.toList());

System.out.println(result);

输出:

[CarModel [year=2019, model=BMW-500-7S-150-Z100], CarModel [year=2019, model=MERCEDES-700-7S-350-Z100]]