Фильтр потока из 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());