У меня есть несколько карт массивов.
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]
Помимо повторения всех ключей карты, проверки того, содержит ли набор ключ, и если не добавить ключ в набор, я не могу придумать никаких более чистых способов сделать это. Есть ли способ сделать это с помощью потоков?
Поскольку вы используете тег 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 Да Это уловка для сбора в виде карты, и в части значения вы просто используете true для дублирования и false для не дублирования
Не могли бы вы объяснить, как работает следующая часть (технически) Collectors.toMap(Function.identity(), x -> false, (a, b) -> true)
@PanagiotisBougioukos x -> false
означает, что если есть уникальный элемент, то верните false, (a, b) -> true
означает, что если a и b равны, это означает, что есть дубликаты, поэтому верните true, для более подробной информации прочитайте это
@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());
}
вам не нужно проверять, содержит ли Set ключ, поскольку элементы Set уникальны. Просто переберите все ключи, добавьте их в набор и используйте результат.