#java #list #algorithm #data-structures #java-8
#java #Список #алгоритм #структуры данных #java-8
Вопрос:
* В качестве предисловия я опубликовал аналогичный вопрос, но на этот раз результат, который я хочу, будет другим. Предположим, у нас есть человек по имени Боб, и у него есть список целых чисел, которые он записал:
bobList = [10, 25, 30, 50]
Скажем, есть 3 других списка случайных целых чисел, которые были сгенерированы системой и помещены в 1 основной список:
list1 = [1, 10, 20, 25, 33, 55]
list2 = [2, 3, 5, 6, 9, 30]
list3 = [25, 30, 50, 100]
List<List<Integer>> masterList = new ArrayList<>()
masterList.add(list1)
masterList.add(list2)
masterList.add(list3)
Можно предположить, что 3 списка чисел, сгенерированных системой, расположены в порядке от наименьшего к наибольшему, а список Боба также от наименьшего к наибольшему. Цель состоит в том, чтобы просмотреть список Боба и посмотреть, содержится ли каждое число, записанное Бобом, в каждом списке в главном списке. Я попробовал это с Java 11 с потоками, чтобы попытаться показать, принадлежит ли каждое целое число в списке Боба каждому из 3 списков, пытаясь вывести его следующим образом
{10=[true, false, false], 25=[true, false, true], 30=[false, true, true] , 50=[false, false, true]}
Я думаю, что это будет что-то вроде списка Боба, но с каждым целым числом, которое он записал, является ключом, а значением является список логических значений, где каждый индекс является соответствующим списком, и если его значение true, то это число, которое написал Боб, находится в списке, и наоборот для false. Но проблема в том, что я новичок в программировании, и, на мой взгляд, вся эта структура данных и алгоритмы действительно мешают мне, и я застрял на этом в течение последнего дня. Может ли кто-нибудь опубликовать решение для этого, где результат будет выглядеть так, как описано? Или, если у вас есть лучшие рекомендации для вывода, который имеет более простой вид, я обязательно хочу его улучшить! Спасибо!
Обновление: я совершенно забыл добавить свою попытку, но я поиграл с этим фрагментом:
List<Map<Boolean, List<Integer>>> test = bobList.stream()
.map(list -> list.stream()
.collect(Collectors.partitioningBy(masterList::contains)))
.collect(Collectors.toList());
test.forEach(System.out::println);
Вывод выглядит примерно так:
{false=[1,20,33,55], true=[10,25]}
{false=[2,3,5,6,9], true=[30]}
{false=[100], true=[25,30,50]}
Как вы можете видеть, этот способ сравнивает 3 списка в masterList с bobList и выводит его как false и true и разделяет те числа, которые есть в bobList, а какие нет. Тем не менее, я попытался перевернуть его и посмотреть, какие числа в bobList находятся в списках masterList, и вывести его так, как я хотел, но я просто застреваю и обхожусь с разными попытками
Частичное решение, которое у меня было, состояло в том, чтобы перейти от списка boblist к списку 1, используя :
masterList.stream().map(l -> l.contains(i)).collect(Collectors.toList()))));
Но я не уверен, где взять соответствующий ключ для списка.
Обновление: Спасибо Хольгеру, я забыл, что вы можете использовать .collect() дважды
Комментарии:
1. Пожалуйста, добавьте свою текущую попытку, даже если она не работает; это показывает ваши собственные усилия.
2. Просто чтобы дать вам несколько условий поиска: вы ищете пересечение нескольких отсортированных наборов. Я не знаю, разрешено ли вам использовать наборы вместо списков или существуют ли другие ограничения для вашей задачи, но одним из способов было бы использовать что-то вроде
[TreeSet
] ( docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util /… ) и егоretainAll
метод. (Однако в этом решении нет потоков).3. Что вы пробовали до сих пор?
4. Я добавил свою попытку выше, пожалуйста, помогите мне, спасибо!
Ответ №1:
Попробуйте разбить проблему на этапы и реализовать каждый шаг! (Псевдокод очень помогает) 🙂 Я дам вам небольшую подсказку:
Ваша цель здесь — выполнить итерацию по списку bobList и проверить, содержит ли list1, list2 и list3 (путем итерации по Masterlist) целое число, и распечатать этот результат. Например, вы можете выполнить итерацию с помощью циклов for.
Как вы можете проверить, содержит ли список это целое число? Может ли помочь что-то вроде метода list.contains()?
Что касается вывода, вы можете выводить его как угодно, если он выглядит красиво и соответствует критериям. например, если вы хотите немного пофантазировать со своим выводом:
10: |true|false|false|
Вы можете распечатать логическое значение сразу во время итераций внутри цикла for.
Ответ №2:
Если вы хотите сделать это с потоками, то решение состоит в том, чтобы передавать bobList
и собирать поток в виде карты. Значения в map сами по себе могут быть сгенерированы потоковой masterList
передачей и отображением в логическое значение, представляющее, находится ли ключ в связанном списке.
Собрать все это вместе:
Map<Integer,List<Boolean>> result = bobList.stream()
.collect(Collectors.toMap(
i -> i,
i -> masterList.stream().map(l -> l.contains(i)).collect(Collectors.toList()))));
По предложению Хольгера: l.contains(i)
может быть заменен на Collections.binarySearch(l, i) >= 0
который ускоряет поиск, полагаясь на тот факт, что он предварительно отсортирован. Но если ваши списки не будут длинными или эта карта не будет создаваться много раз, я бы ожидал, что разница будет минимальной.
Вы также упоминаете в комментариях (а не в исходном вопросе), что хотите, чтобы порядок ключей сохранялся. Вы могли бы сделать это, явно используя LinkedHashMap
.
Комментарии:
1. Отсутствуют некоторые закрывающие скобки. Кроме того, поскольку в OP указано, что списки гарантированно будут в порядке возрастания, вы можете заменить
l -> l.contains(i)
наl -> Collections.binarySearch(l, i)>=0
.2.@IHaveAQuestion нет, чтобы получить результат по порядку, вам нужен a
Map
, который поддерживает порядок, т. Е.Collectors.toMap(i -> i, i -> masterList.stream().map(l -> l.contains(i)).collect(Collectors.toList()), (a,b) -> { throw new IllegalStateException("duplicate"); }, LinkedHashMap::new))
.binarySearch
Использует отсортированную природу исходных списков, чтобы быть быстрее, чем линейный поиск, выполняемыйList.contains
.