Мне не совсем понятно, что требуется для "использования только интерфейса Set
", но я предполагаю, что это означает, что повторяющиеся символы должны быть возвращены в Set
.Есть несколько способов сделать это.Первый - это простой цикл над символами входной строки.Он использует функцию Set.add
, которая возвращает true
, если набор был изменен, и false
, если это не так;это означает, что операция add
, которая возвращает false
, является дубликатом.
static Set<Character> dups0(String input) {
Set<Character> dups = new HashSet<>();
Set<Character> seen = new HashSet<>();
for (char ch : input.toCharArray()) {
if (! seen.add(ch)) {
dups.add(ch);
}
}
return dups;
}
Существует потоковый способ сделать это, что по сути то же самое, что выражено в виде потока:
static Set<Character> dups1(String input) {
Set<Character> seen = new HashSet<>();
return input.chars()
.mapToObj(ch -> (char)ch)
.filter(ch -> !seen.add(ch))
.collect(toSet());
}
Некоторые люди могут посчитать это неприятным, поскольку его операция фильтра вызывает побочные эффекты.Кроме того, если это выполняется параллельно, результатом должно быть что-то вроде ConcurrentHashMap.newKeySet
.
Альтернативой является генерация таблицы частот символов и удаление всех записей, которые встречаются только один раз:
static Set<Character> dups2(String input) {
Map<Character, Long> map = input.chars()
.mapToObj(i -> (char)i)
.collect(groupingBy(ch -> ch, counting()));
map.values().removeIf(v -> v == 1);
return map.keySet();
}
Обратите внимание, что при этом используется массовая операция сбора в представлении сбора значений карты.Если вам не нравится мутация, есть способ сделать это с помощью чистых потоков:
static Set<Character> dups3(String input) {
Map<Character, Long> map = input.chars()
.mapToObj(i -> (char)i)
.collect(groupingBy(ch -> ch, counting()));
return map.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.map(Map.Entry::getKey)
.collect(toSet());
}