如何仅捕获 ArrayList 中的重复元素?

Fru*_*ang 4 java arraylist duplicates java-stream

我需要在我的ArrayList. 我不需要删除重复项,我需要将它们添加到另一个ArrayList. 下面是一个例子:

ArrayList<String> var = new ArrayList<>();
var.add("a");
var.add("b");
var.add("b");
var.add("c");
Run Code Online (Sandbox Code Playgroud)

因此,如您所见,有 2 个重复元素(b 和 b)。我需要将它们添加到另一个 ArrayList。

所产生的ArrayList在这种情况下应该是[b,b]。我怎样才能做到这一点?

dre*_*ash 7

方法一:

这样的事情就足够了:

    for(String s : var )
        if(Collections.frequency(var, s) > 1)
            duplicates.add(s);
Run Code Online (Sandbox Code Playgroud)

并使用流:

var.stream().filter(s -> frequency(var, s) > 1).collect(toList());
Run Code Online (Sandbox Code Playgroud)

一个正在运行的例子:

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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

[b, b]
Run Code Online (Sandbox Code Playgroud)

想法如下,考虑列表,并为每个元素检查它们在列表中的频率,如果它们出现不止一次,则添加到重复列表中。

方法二:

一个不太干净的解决方案,但具有更好的时间复杂度是使用该字符串的每个频率的字符串映射,然后基于该映射构建重复列表:

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());
}
Run Code Online (Sandbox Code Playgroud)

方法三:

具有线性时间复杂度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);
Run Code Online (Sandbox Code Playgroud)

可以利用Set.add方法语义,即:

If this set already contains the element, the call leaves the set
     unchanged and returns {@code false}.
Run Code Online (Sandbox Code Playgroud)

将上述代码缩短为仅:

    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);  
Run Code Online (Sandbox Code Playgroud)