Сортировка четных элементов массива в Java

Всем привет! В данный момент я решаю такую задачу:нужно реализовать публичный статический метод getSameParity(), который принимает на вход массив чисел и возвращает новый, состоящий из элементов, у которых такая же чётность, как и у первого элемента входного массива. Если на вход был передан пустой массив, метод возвращает также пустой массив.

Пример работы программы:

int[] numbers1 = {};
App.getSameParity(numbers1); // []
 
int[] numbers2 = {1, 2, 3};
App.getSameParity(numbers2); // [1, 3]
 
int[] numbers3 = {1, 2, 8};
App.getSameParity(numbers3); // [1]
 
int[] numbers4 = {2, 2, 8};
App.getSameParity(numbers4); // [2, 2, 8]
 
int[] numbers5 = {-3, 2, 1};
App.getSameParity(numbers5); // [-3, 1]

Уточнение к задаче:

Проверку чётности следует выполнять, используя остаток от деления на 2: item % 2 == 0 В массиве могут находится отрицательные числа. Для работы с ними использовать метод нахождения модуля Math.abs()

  Math.abs(-1); // 1

  Math.abs(1); // 1

  Math.abs(0); // 0

Так как мы не знаем заранее, какое количество элементов будет в новом массиве, можно изначально создать массив с "запасом", а затем отрезать лишнее. Для этого может понадобиться метод Arrays.copyOfRange(), который принимает на вход массив чисел и возвращает часть его элементов в виде нового массива:

int[] numbers = {3, 7, 8, 9, 2, 1};

// получаем элементы с 1-го индекса включительно по 4-й не включительно 

var range = Arrays.copyOfRange(numbers, 0, 4);

System.out.println(Arrays.toString(range));

// => [3, 7, 8, 9]

Мое решение:


package com.arrays.problem6;

import java.util.Arrays;

public class App {

    public static void main(String[] args) {
  
        }

    public static Integer getSameParity(int[] numbers){

            int i = 0, j = numbers.length - 1;

            if(Math.abs(numbers[i]%2)!= Math.abs(numbers[j])% 2) {
                i++;
                if(Math.abs(numbers[i])% 2 == Math.abs(numbers[j])% 2) {
                    return numbers[i-1];
                }
                j--;
                if(Math.abs(numbers[i])%2 == Math.abs(numbers[j])%2) {
                    return numbers[j+1];
                }
            }

            while(i < j) {
                if(Math.abs(numbers[i])%2 != Math.abs(numbers[j])%2) {
                    if(Math.abs(numbers[i])%2 == Math.abs(numbers[0])%2) {
                        return numbers[j];
                    }else {
                        return numbers[i];
                    }
                }
                i++;
                j--;
            }
        int[] range=Arrays.copyOfRange(numbers,0,4);
        System.out.println(Arrays.toString(range));
            return numbers[i];

        }
    }

Программа не работает, хотя подозреваю,что я близок к правильному решению.Помогите мне пожалуйста решить эту задачу.


Ответы (2 шт):

Автор решения: Stanislav Volodarskiy

Выделять с запасом, затем обрезать - не наш метод. Наш метод - сосчитать длину ответа, выделить сколько надо, заполнить.

Проверка чётности отрицательных чисел ничем не отличается от проверки чётности положительных. Для некоторых других остатков (больших двух) некоторая разница есть, но тут не надо беспокоиться.

public static int[] getSameParity(int[] numbers) {
    if (numbers.length == 0) {
        return new int[0];
    }

    boolean parity = isEven(numbers[0]);

    int n = 0;
    for (int v : numbers) {
        if (isEven(v) == parity) {
            ++n;
        }
    }

    int[] answer = new int[n];
        
    int j = 0;
    for (int v : numbers) {
        if (isEven(v) == parity) {
            answer[j++] = v;
        }
    }
    assert(j == n);

    return answer;
}

private static boolean isEven(int n) {
    return n % 2 == 0;
}

Код грешит дублированием - два одинаковых цикла с одинаковыми условиями. Это породная особенность C-подобных языков в отсутствии нормальных контейнеров. От дублирования можно избавиться, да решение станет значительно сложнее. А мы тут учимся, оставим как есть.

Дополнение

Избавимся от дублирования совсем:

public static int[] getSameParity(int[] numbers) {
    if (numbers.length == 0) {
        return new int[0];
    }
    boolean parity = isEven(numbers[0]);
    return Arrays.stream(numbers).filter(v -> isEven(v) == parity).toArray();
}
→ Ссылка
Автор решения: Igor

Можно так сделать

private static int[] getSameParity(int[] numbers) {
    if (numbers.length == 0) return new int[]{};
    return Arrays.stream(numbers).filter(getIntPredicate(numbers[0])).toArray();
}

private static IntPredicate getIntPredicate(int firstElement) {
    return number ->  Math.abs(number % 2) == Math.abs(firstElement % 2);
}

либо так, что в общем одно и тоже почти

private static int[] getSameParity(int[] numbers) {
    if (numbers.length == 0) return new int[]{};
    int remainder = getRemainder(numbers[0]);
    return Arrays.stream(numbers).filter(value -> getRemainder(value) == remainder).toArray();
}

private static int getRemainder(int n) {
    return  Math.abs(n % 2);
}
→ Ссылка