1

How can I get the indexes of all duplicate elements by using the Java stream API?

For example, we have:

List<Integer> input =
        new ArrayList<>(Arrays.asList(312, 312, 195, 195, 195, 851, 335, 851, 99));

I could group same elements like this:

result = input.stream().collect(Collectors.groupingBy(input::indexOf))
//result = {0=[312, 312], 2=[195, 195, 195], 5=[851, 851], 6=[335], 8=[99]}

But I want get a result like this:

{312=[0, 1], 195=[2, 3, 4], 851=[5, 7]}

or just like this:

(0,1,2,3,4,5,7)

How can I do this?

5 Answers 5

4

You can Use IntStream

Map<Integer, List<Integer>> map = IntStream.range(0, input.size())
                .boxed()
                .collect(Collectors.groupingBy(i -> input.get(i), HashMap::new,
                        Collectors.toCollection(ArrayList::new)));

// output : {99=[8], 851=[5, 7], 195=[2, 3, 4], 312=[0, 1], 335=[6]}

Once you have all the values and their indexes you can simply filter out the entries which have more than 1 value.
Full example:

Map<Integer, List<Integer>> map = IntStream.range(0, input.size())
                .boxed()
                .collect(Collectors.groupingBy(i -> input.get(i), HashMap::new,
                        Collectors.toCollection(ArrayList::new)))
                .entrySet()
                .stream()
                .filter(e -> e.getValue().size()>1)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Sign up to request clarification or add additional context in comments.

2 Comments

great, thx! it's give me fresh lookup on streams, and will help to lean it better
.collect(Collectors.groupingBy(input::get, Collectors.toList())) would usually suffice; there's rarely a need to specify that it's should specifically be a HashMap or ArrayList.
2

Another approach using Collections.frequency

int[] dupIndexes = IntStream.range(0, input.size())
                            .filter(i -> Collections.frequency(input, input.get(i)) > 1)
                            .toArray();

1 Comment

Note that while this is a straightforward approach, it's not very efficient. It needs to iterate over the entire list for each element of the list to calculate the frequency of that item. This gives it a time complexity of O(n^2). Much more efficient algorithms exist to solve this problem.
0

Looks like it's quite easy to solve by just for loop. Just keep a Map with input value as a key and it's index as a value of map:

Set<Integer> result = new HashSet<>();
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < input.size(); i++) {
    if (map.containsKey(input.get(i))) {
        result.add(map.get(input.get(i)));
        result.add(i);
    } else {
        map.put(input.get(i), i);
    }
}
System.out.println(result);

Output

[0, 1, 2, 3, 4, 5, 7]

Comments

0

You can try below code -

     List<Integer> input = new ArrayList<>(Arrays.asList(312, 312, 195, 195, 195, 851, 335, 851, 99));
    result = IntStream.range(0, input.size()).boxed()
            .collect(Collectors.groupingBy(input::get, HashMap::new,
                    Collectors.toList()));

Comments

0
    HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
    List<Integer> ls = null;
    for (int i = 0; i < input.size(); i++) {
        if (map.get(input.get(i)) != null) {
            ls = map.get(input.get(i));
        } else {
            ls = new ArrayList<Integer>();
        }
        ls.add(i);
        map.put(input.get(i), ls);
    }
    System.out.println(map);

2 Comments

sorry dude, but i searching stream solution (on studying practice) and i find it in answers
no worries, glad you got your solutions & I too learned few new things,

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.