Home > Enterprise >  Why I get this error : error: bad operand types for binary operator '%'?
Why I get this error : error: bad operand types for binary operator '%'?

Time:05-08

I'm currently working on an exercise to sort only the odd element of an array of int. The program shouldn't affect the even elements, For example:

[5, 3, 8, 0, 1] --> [1, 3, 8, 0, 5]

However, when I run the following code, the compiler gives the following error:

Main.java:21: error: ')' expected
        int [] res = Arrays.asList(array).stream().mapToInt((x[0]) -> x[0]%2 == 0 ? x[0] : listInt.get(  j)).collect(Collectors.toList()).toArray();
                                                                  ^
Main.java:21: error: not a statement
        int [] res = Arrays.asList(array).stream().mapToInt((x[0]) -> x[0]%2 == 0 ? x[0] : listInt.get(  j)).collect(Collectors.toList()).toArray();
                                                                                  ^
Main.java:21: error: ';' expected
        int [] res = Arrays.asList(array).stream().mapToInt((x[0]) -> x[0]%2 == 0 ? x[0] : listInt.get(  j)).collect(Collectors.toList()).toArray();
                                                                                                           ^
3 errors

Here's my code:

public static void main(String[] args) {
    int[] array = new int[]{ 5, 3, 1, 8, 0 };
    int j = 0;
    List<Integer> listInt = Arrays.stream(array).filter(x -> x%2 != 0).sorted().boxed().collect(Collectors.toList());
    int [] res = Arrays.asList(array).stream().mapToInt(x -> x%2 == 0 ? x : listInt.get(  j)).collect(Collectors.toList()).toArray();   
}

Could you help me to fix those error?

CodePudding user response:

In your statement with Arrays.asList(array) you're creating a List where each element is an array of int, so when you're streaming the List, the stream expects each element to be int[], not int. In your case, the stream only contains the array variable. When you're performing x -> x % 2 == 0, you're not applying it on the array's elements but on the array itself; thus giving you the error.

Besides, lambda expressions only allow to use final or effectively final variables, i.e. variables whose value does not change. Your j expression within the stream won't be accepted either.

This is a fixed version of your code:

public class Main {
    public static void main(String[] args) {
        int[] array = new int[]{5, 3, 1, 8, 0};

        //Passing to list returned by the stream to a PriorityQueue to store the odd numbers sorted with their natural order.
        //In this way, there is no need to sort the elements within the stream and we can use the queue as an effectively final variable while still polling its elements
        PriorityQueue<Integer> queue = new PriorityQueue<>(Arrays.stream(array).filter(x -> x % 2 != 0).boxed().collect(Collectors.toList()));

        //Declaring and initializing the result array in order to pass it to the toArray method
        Integer[] res = new Integer[0];

        //For each element of the stream we return the even numbers while we pop the odd sorted numbers from the queue
        res = Arrays.stream(array).boxed().map(x -> x % 2 == 0 ? x : queue.poll()).collect(Collectors.toList()).toArray(res);

        //Printing the result on screen
        System.out.println(Arrays.toString(res));
    }
}

CodePudding user response:

There are essentially 3 changes you need to make:

  1. Change Arrays.stream(array) to IntStream.of(array)
  2. Change int j = 0; to int[] j = {0};
  3. Change j to j[0]

The first change is needed because Arrays.stream(array) creates a stream of int[] with 1 element, but you want a stream of int, so use IntStream directly.

The second change is more subtle. Because all terms in a lambda must be effectively final - ie you can't change their value - j won't compile. By making j an int[] you can change its contents without changing the reference to j.

The third change is a logic problem: j (or j[0] in the new version) increments before its use and so will cause an out of bounds exception for the final operation.

Your code fixed:

int[] j = {0};
int[] odds = IntStream.of(array).filter(x -> x%2 != 0).sorted().toArray();
int [] res = IntStream.of(array).map(x -> x%2 == 0 ? x : odds[j[0]  ]).toArray();

Note that you don't need to box int to Integer, and I renamed the cryptic listInt to odds for readability.

The "proper" solution is to change j to AtomicInteger - similarly the reference to j won't change, but its contents may change:

AtomicInteger j = new AtomicInteger();
int[] odds = IntStream.of(array).filter(x -> x%2 != 0).sorted().toArray();
int [] res = IntStream.of(array).map(x -> x%2 == 0 ? x : odds[j.getAndIncrement()]).toArray();
  • Related