Как можно отфильтровать 2 колекции через Stream API, и в конечном итоге создать колекцию Обьектов исходя из данных
Method must return a list of NumberPair objects by the following rules:
the first element of the pair belongs to integerList1; the second element of the pair belongs to integerList2; both elements end with the same digit. Parameter:
integerList1 is a list of positive integers; integerList2 is a list of positive integers.
Proceed to NumberPair class and implement its content, it contains the following fields:
<value_1>, <value_2>.
Example
Input:
integerList1 = [1, 2, 33, 44] integerList2 = [11, 22, 13]
Output:
[ NumberPair(1, 11), NumberPair(2, 22), NumberPair(33, 13) ]
У меня получилось вот так:
List<String > first = integerList1.stream().map(x->x.toString()).collect(Collectors.toList());
List<String > second = integerList2.stream().map(x->x.toString()).collect(Collectors.toList());
List<String> list = Stream.concat(first.stream(), second.stream()).collect(Collectors.groupingBy(x->x.charAt(x.length()-1)))
.entrySet().stream().filter(x->x.getValue().size() > 1).flatMap(x->x.getValue().stream()).collect(Collectors.toList());
list.stream().mapToInt(x->Integer.parseInt(x)).mapToObj((x,y)->new NumberPair(x,y));
Входные значения я брал из условия.
- Для начала я создал 2 листа Стрингов что бы иметь возможноть взять последние элементы для сравнения.
- Создал поток из двух этих колекций.
- И сгрупировал по последним значениям
- Получил 1 поток из значений Map (где 1 элемент - это от 1 колекции и 2 - от 2 колекции) --вывод листа: [1, 11, 2, 22, 33, 13]
Проблемы:
- Как лучше можно отфильтровать 2 колекции сразу (ссылаясь на значения друг друга)?
- Как создать набор обьект (PairNumber) в условиях потока исходя с данных в потоке?
- Если есть какой-то более умный способ решения, буду вам благодарин)
Ответы (2 шт):
А зачем столько всего? Преобразование в Стринг и назад в Инт - недешевое с точки зрения скорости и ресурсов удовольствие. Может так:
List<Integer> integerList1 = Arrays.asList(1, 2, 33, 44);
List<Integer> integerList2 = Arrays.asList(11, 22, 13, 3);
Map<Integer, List<Integer>> collect = integerList2.stream()
.collect(Collectors.groupingBy(k -> k % 10));
List<NumberPair> result = integerList1.stream()
.filter(i -> collect.get(i % 10) != null)
.map(i -> new NumberPair(i, collect.get(i % 10).get(0)))
.collect(Collectors.toList());
Единственная проблема в том, что я не понимаю, как поступить, если несколько чисел заканчиваются на одинаковые цифры? Посему собираю вторую коллекцию в Map, там смотрите сами
Можно воспользоваться коллектором Collectors.collectingAndThen, в котором сперва следует получить простую мапу с ключом - остатком от деления на 10 Map<Integer, List<Integer>>, и затем преобразовать её значения в нужные объекты. При этом хорошо, чтобы был некий отдельный метод для преобразования списков в NumberPair.
Допустим, класс NumberPair определен как кортеж (record) с конструктором, принимающим список целых чисел:
public record NumberPair(Integer first, Integer second){
NumberPair(List<Integer> list) {
this(list.get(0), list.get(1));
}
}
Тогда можно написать такой метод для произвольного числа списков:
public static List<NumberPair> convert(List<Integer> ... lists) {
return Stream.of(lists) // Stream<List<Integer>>
.flatMap(List::stream) // Stream<Integer>
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(i -> i % 10), // Map<Integer, List<Integer>>
(map) -> map.values()
.stream() // Stream<List<Integer>>
.filter(lst -> lst.size() == 2)
.map(NumberPair::new) // Stream<NumberPair>
.collect(Collectors.toList())
));
}
Тест:
List<Integer> list1 = Arrays.asList(1, 2, 33, 44);
List<Integer> list2 = Arrays.asList(11, 22, 13);
System.out.println(convert(list1, list2));
Результат:
[NumberPair[first=1, second=11], NumberPair[first=2, second=22], NumberPair[first=33, second=13]]