Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Note able to get Distinct int[] from List<int[]>

Tags:

java-8

I am trying to get distinct List with unique int[], but I am still getting duplicates.

List<Integer> set1 = Arrays.asList(2, 3, 4, 5, 10, 4, 5, 6, 4);
List<Integer> count = new ArrayList<>();
List<int[]> combination = set1.stream().flatMap(i -> set1.stream().
            flatMap(j -> set1.stream().map(k -> new int[] { i, j, k }))) 
                                      .distinct().collect(Collectors.toList());

My logic to get required elements from the combined list of int[] is the numbers in array should be consecutive with difference of 1.

Ex: {2,3,4}

But in my final list the {2,3,4} is coming 3 times , it is obvious. I want to winnow the occurrences of 3 times {2,3,4} to 1. SO i wrote the below logic. Still there are many elements which are in consecutive form {4,5,6}, i want them also to be only once counted.

 List<int[]> combination1 = combination.stream().distinct().collect(Collectors.toList());
        combination1.stream().filter(i -> Collections.frequency(combination, i) == 1).forEach(s -> {
            if (s[1] - s[0] == 1 && s[2] - s[1] == 1 && s[2] - s[0] == 2) {
                count.add(1);
            } else {
                count.add(0);
            }
        });
        System.out.println(count.stream().mapToInt(Integer::intValue).sum());

I am getting the unique elements as 15, but it should be 3.

My final List<int[]> should contain only : {2,3,4} , {3,4,5} , {4,5,6} and hence count should be three.

like image 219
Joka Lee Avatar asked Jan 01 '23 21:01

Joka Lee


2 Answers

Here's the first line of distinct()'s documentation:

Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.

Now, because you're running it on a Stream<int[]>, int[].equals would have to return true when two int arrays have the same content. But it doesn't (see this). You can solve it by using a list before distinct(), and mapping afterwards (using Integer[] here, but a different mapping is needed for int[]):

List<Integer[]> combination = set1.stream()
    .flatMap(i -> set1.stream()
                      .flatMap(j -> set1.stream().map(k -> Arrays.asList(i, j, k))))
    .distinct()
    .map(l -> l.toArray(new Integer[0]))
    .collect(Collectors.toList());
like image 83
ernest_k Avatar answered Feb 15 '23 23:02

ernest_k


As stated in this answer, int[] arrays do not have the require equality for distinct(). However, IntBuffer can wrap int[] arrays and provide the value based equality. So you can get distinct arrays using the sequence map(IntBuffer::wrap).distinct().map(IntBuffer::array), to wrap the arrays, eliminate duplicates and unwrap the arrays.

However, that problem was part of an entirely unnecessary step, as you weren’t focusing on the actual problem you want to solve.

To get all tuples of consecutive value, you can simply use

List<Integer> set1 = Arrays.asList(2, 3, 4, 5, 10, 4, 5, 6, 4);

int[] ascending = set1.stream().mapToInt(Integer::intValue).sorted().distinct().toArray();

List<int[]> combination = IntStream.rangeClosed(0, ascending.length - 3)
    .mapToObj(ix -> Arrays.copyOfRange(ascending, ix, ix + 3))
    .filter(a -> a[0] + 1 == a[1] && a[1] + 1 == a[2])
    .collect(Collectors.toList());

combination.forEach(a -> System.out.println(Arrays.toString(a)));

Instead of creating 729 combinations of all values, to eliminate redundant combinations, followed by eliminating nonmatching combinations, it generates only the four possible ascending combinations in the first place. Then, it filters these, to accept sequences of consecutive numbers only.

So the last statement will print

[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
like image 39
Holger Avatar answered Feb 15 '23 22:02

Holger