Получить список повторяющихся ключей карты из нескольких карт

У меня есть несколько карт массивов.

Map<String, List<String>> map1 = new HashMap<>();
Map<String, List<String>> map2 = new HashMap<>();
Map<String, List<String>> map3 = new HashMap<>();
Map<String, List<String>> map4 = new HashMap<>();

Я хочу получить список повторяющихся ключей карты из нескольких карт.

Например

map1.put("k0", Arrays.asList("a0", "a1"));
map1.put("k1", Arrays.asList("b0", "b1"));

map2.put("k1", Arrays.asList("z1", "z2"));
map2.put("k2", Arrays.asList("z1", "z2"));

map3.put("k1", Arrays.asList("z1", "z2"));
map3.put("k3", Arrays.asList("z1", "z2"));

map4.put("k3", Arrays.asList("z1", "z2"));
map4.put("k4", Arrays.asList("z1", "z2"));

map5.put("k0", Arrays.asList("z1", "z2"));
map5.put("k5", Arrays.asList("z1", "z2"));

// Expected output is 
List: [k0, k1, k3]

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

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

Sergey Grinev 16.12.2020 08:00
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
1
786
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Поскольку вы используете тег java-stream, вы можете решить свою проблему следующим образом:

Set<String> duplicateKeys = Stream.of(map1.keySet(), map2.keySet(), map3.keySet(), map4.keySet(), map5.keySet())
        .flatMap(Set::stream)
        .collect(Collectors.toMap(Function.identity(), x -> false, (a, b) -> true))
        .entrySet().stream()
        .filter(Map.Entry::getValue)
        .map(Map.Entry::getKey)
        .collect(Collectors.toSet());

Выход

[k0, k1, k3]

.collect(Collectors.toMap(Function.identity(), x -> false, (a, b) -> true)) это возвращает Map<String, Boolean> возвращает ключ и true если дублируется и false если нет, то вы просто фильтруете, чтобы получить только записи, где значение истинно .filter(Map.Entry::getValue), которые представляют дубликаты.

Вау, спасибо. Можете ли вы немного объяснить, как это работает, особенно «Collectors.toMap(Function.identity(), x -> false, (a, b) -> true)»?

villabilla 16.12.2020 08:30

@villabilla Да Это уловка для сбора в виде карты, и в части значения вы просто используете true для дублирования и false для не дублирования

Youcef LAIDANI 16.12.2020 08:48

Не могли бы вы объяснить, как работает следующая часть (технически) Collectors.toMap(Function.identity(), x -> false, (a, b) -> true)

Panagiotis Bougioukos 16.12.2020 09:34

@PanagiotisBougioukos x -> false означает, что если есть уникальный элемент, то верните false, (a, b) -> true означает, что если a и b равны, это означает, что есть дубликаты, поэтому верните true, для более подробной информации прочитайте это

Youcef LAIDANI 16.12.2020 09:50
Ответ принят как подходящий
@SafeVarargs
private static Set<String> findDuplicateKeys(Map<String, ?>... maps) {
    Set<String> keys = new HashSet<>();
    return Arrays.stream(maps)
            .flatMap(map -> map.keySet().stream())
            .filter(key -> !keys.add(key))
            .collect(Collectors.toSet());
}

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

Или вы можете попробовать это. Создайте поток карт, затем flatMap его в поток ключей, затем соберите ключи в Map подсчет количества каждого ключа, затем поток этого EntrySet, Set<Map.Entry>, отфильтруйте по количеству вхождений ключей, сопоставьте это к ключевым значениям и собрать в список. Это должно работать с .parallel().

 private List<String> findDups(Map<String, ?>... maps) {
 return Arrays.asList(maps).stream()
  .flatMap(m->m.keySet().stream())
  .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
  .entrySet().stream()
  .filter(es->es.getValue() > 1)
  .map(es->es.getKey())
  .collect(Collectors.toList());
} 

Другие вопросы по теме