Фильтр потока из 1 списка на основе другого списка

Я отправляю свой запрос после поиска в этом форуме и google, но не смог его решить. например: Link1 Link2 Link3

Я пытаюсь отфильтровать список 2 (несколько столбцов) на основе значений в списке 1.

List1:
 - [Datsun]
 - [Volvo]
 - [BMW]
 - [Mercedes]

List2: 
 - [1-Jun-1995, Audi, 25.3, 500.4, 300]
 - [7-Apr-1996, BMW, 35.3, 250.2, 500]
 - [3-May-1996, Porsche, 45.3, 750.8, 200]
 - [2-Nov-1998, Volvo, 75.3, 150.2, 100]
 - [7-Dec-1999, BMW, 95.3, 850.2, 900]

expected o/p:
 - [7-Apr-1996, BMW, 35.3, 250.2, 500]
 - [2-Nov-1998, Volvo, 75.3, 150.2, 100]
 - [7-Dec-1999, BMW, 95.3, 850.2, 900]

код

// List 1 in above eg
List<dataCarName> listCarName = new ArrayList<>(); 
// List 2 in above eg
List<dataCar> listCar = new ArrayList<>(); 

// Values to the 2 lists are populated from excel

List<dataCar> listOutput = listCar.stream().filter(e -> e.getName().contains("BMW")).collect(Collectors.toList());

В приведенном выше коде, если я предоставляю определенное значение, я могу фильтровать, но не уверен, как проверить, не исчезло ли имя автомобиля в списке 2 в списке 1.

Надеюсь, что проблема, с которой я сталкиваюсь, ясна, ожидайте указания (я все еще относительно новичок в Java, поэтому прощайте, если вышеприведенный запрос очень простой).

Edit Я считаю, что ссылка-3, приведенная выше, должна быть решена, но в моем случае она не работает. Возможно, потому что значения в списке-1 заполняются как [email protected] и т.д. Я могу получить значение в удобочитаемом формате только тогда, когда я делаю forEach в списке 1, вызывая метод getName.

Ответ 1

Непонятно, почему у вас есть List<DataCarName> на первом месте вместо List/Set<String>.

Предикат, который вы должны предоставить, должен проверить, если для соответствующего экземпляра транспортного средства данных есть его имя в списке.

e -> e.getName().contains("BMW") будет проверять, содержит ли только название автомобиля данных BMW, что вы не хотите. Ваша первая попытка может быть

e -> listCarName.contains(e.getName())

но поскольку listCarName является List<DataCarName> и e.getName() строкой (я полагаю), в результате вы получите пустой список.

Первый вариант, который у вас есть, - это изменить предикат, чтобы вы получили поток из списка имен автомобильных данных, сопоставляли их с их строковым представлением и проверяли, что любое из этих имен соответствует текущему имени экземпляра транспортного средства в настоящее время фильтрует:

List<DataCar> listOutput =
    listCar.stream()
           .filter(e -> listCarName.stream().map(DataCarName::getName).anyMatch(name -> name.equals(e.getName())))
           .collect(Collectors.toList());

Теперь это очень дорого, потому что вы создаете поток для каждого экземпляра в конвейере потока данных. Лучшим способом было бы построить Set<String> с именем автомобиля вверх, а затем просто использовать contains как предикат на этом наборе:

Set<String> carNames = 
    listCarName.stream()
               .map(DataCarName::getName)
               .collect(Collectors.toSet());

List<DataCar> listOutput =
     listCar.stream()
            .filter(e -> carNames.contains(e.getName()))
            .collect(Collectors.toList());

Ответ 2

в вашем типе DataCar, возвращает getName() тип перечисления String или DataCarName? Если это перечисление, вы можете следовать подходу Alexis C, но вместо создания HashSet с использованием Collectors.toSet() создайте EnumSet, который дает производительность O (1). Изменив предложение Алексиса, результат будет выглядеть следующим образом:

Set<DataCarName> carNames = 
    listCarName.stream()
               .collect(Collectors.toCollection(
                   ()-> EnumSet.noneOf(DataCarName.class)));

List<DataCar> listOutput =
    listCar.stream()
               .filter(car -> carNames.contains(car.getName()))  
               .collect(Collectors.toList());