Approach 1:
Something like this is enough:
for(String s : var )
if(Collections.frequency(var, s) > 1)
duplicates.add(s);
and with streams:
var.stream().filter(s -> frequency(var, s) > 1).collect(toList());
a running example:
public static void main(String[] args) {
List<String> var = Arrays.asList("a", "b", "b", "c");
List<String> dup = var.stream().filter(s -> Collections.frequency(var, s) > 1).collect(Collectors.toList());
System.out.println(dup);
}
Output:
[b, b]
The idea is as follows, go thought the list, and for each element check their frequency on the list, if they appear more than once add to list of duplicates.
Approach 2:
A less cleaner solution, but with a better time complexity is to use a Map of the string per frequency of that string, and then build the duplicate list base on that Map:
List<String> dup = new ArrayList<>();
Map<String, Long> frequencies =
var.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
for (Map.Entry<String, Long> entry : frequencies.entrySet()){
for(int i = 0; i < entry.getValue() && entry.getValue() > 1; i++)
dup.add(entry.getKey());
}
Approach 3:
With linear time complexity O(N)
:
Set<String> set = new HashSet <>();
List<String> duplicates = new ArrayList<>();
Set<String> is_duplicated = new HashSet <>();
var.forEach(s -> {
if(set.contains(s)) {
is_duplicated.add(s);
duplicates.add(s);
}
else
set.add(s);
});
duplicates.addAll(is_duplicated);
System.out.println(duplicates);
One can take advantage of the Set.add
method semantics, namely:
If this set already contains the element, the call leaves the set
unchanged and returns {@code false}.
To shorten the above code to only:
Set<String> set = new HashSet <>();
List<String> duplicates = new ArrayList<>();
Set<String> to_add = new HashSet<>();
var.forEach(s -> {
if(!set.add(s)) {
to_add.add(s);
duplicates.add(s);
}
});
duplicates.addAll(to_add);
System.out.println(duplicates);