javaarraylistjava-stream

How can I use Java streams to determine duplicate and non-duplicate items from a list?


I have been given this excercise: The vector A = [1,2,5,2,4,2,1,3,6,1,4] is given. Write the function that displays in a vector B all the unique elements and in another vector C all the values that have been repeated without repetition.

The unique vector should be: [5,3,6] and the duplicate vector: [1,2,4].

I have used ArrayList to work with and I cant figure out how to solve this exercise.

Code so far:

 ArrayList<Integer> A=new ArrayList<>(Arrays.asList(1,2,5,2,4,2,1,3,6,1,4));
 List<Integer> B1=A.stream().distinct().collect(Collectors.toList());

Solution

  • I wouldn't use Stream for this. For best performance, I'd use two Sets.

    List<Integer> a = new ArrayList<>(Arrays.asList(1,2,5,2,4,2,1,3,6,1,4));
    
    Set<Integer> b = new LinkedHashSet<>();
    Set<Integer> c = new LinkedHashSet<>();
    for (Integer i : a)
        if (! b.add(i))
            c.add(i);
    
    System.out.println(b);
    System.out.println(c);
    

    Output

    [1, 2, 5, 4, 3, 6]
    [2, 1, 4]
    

    Of course, if you must use Stream API, then this might do.

    Map<Integer, Long> map = a.stream().collect(Collectors.groupingBy(
            Function.identity(), LinkedHashMap::new, Collectors.counting()));
    List<Integer> b = new ArrayList<>(map.keySet());
    List<Integer> c = map.entrySet().stream().filter(e -> e.getValue() > 1)
            .map(Entry::getKey).collect(Collectors.toList());
    

    Output

    [1, 2, 5, 4, 3, 6]
    [1, 2, 4]
    

    The order of b is the same for both, i.e. the order of the first occurrence of a value.

    The order of c differs, since the first solution has the order of occurrence of the first repeat, while the second solution has the same order as b, i.e. the order of the first occurrence of a value.


    UPDATE

    From comment:

    The unique Array should be [5,3,6], and the duplicate Array [1,2,4]

    To get that result, add the following statement to the first version:

    b.removeAll(c);
    

    Output

    [5, 3, 6]
    [2, 1, 4]
    

    Change the code for building b in the second version to:

    List<Integer> b = map.entrySet().stream().filter(e -> e.getValue() == 1)
            .map(Entry::getKey).collect(Collectors.toList());
    

    Output

    [5, 3, 6]
    [1, 2, 4]