Как выбрать те числа из массива, которые лежат в заданом диапазоне?
Задача:
Дан массив возрастающих чисел. Даны два числа. Написать метод, который из данного массива достанет ту часть, которая лежит между данными числами вкл.
Моё решение:
public static int[] getSubArrayBetween(int[] numbers, int start, int end) {
int k = 0;
int[] result = new int[k];
for (int i = 0; i <= numbers.length; i++) {
if (numbers[i] >= start && numbers[i] <= end) {
result[k] = numbers[i];
}
}
return result;
}
}
Подскажите, что я делаю не так?
Ответы (2 шт):
Так как мы заранее не знаем, сколько чисел может лежать между заданными двумя числами start и end, то есть два варианта.
- Использовать массив, но выделить заранее очень много памяти. Разумеется, такой подход очень плох, и поэтому его мы рассматривать не будем.
- Использовать коллекции: они могут расширяться "на ходу", таким образом, сколько чисел будет лежать между
startиend, - ровно столько мы и добавим.
Ниже приведён вариант, как можно исправить ваш код, используя коллекции.
public static List<Integer> getSubArrayBetween(int[] numbers, int start, int end) {
List<Integer> integers = new ArrayList<>();
for (Integer integer : numbers) {
if (integer >= start && integer <= end) {
integers.add(integer);
}
}
return integers;
}
Чтобы вернуть именно массив, код можно изменить так:
public static Integer[] getSubArrayBetween(int[] numbers, int start, int end) {
List<Integer> integers = new ArrayList<>();
for (Integer integer : numbers) {
if (integer >= start && integer <= end) {
integers.add(integer);
}
}
return integers.toArray(new Integer[0]);
}
Хотя в таком варианте возвращается массив оболочек Integer, а не примитивного типа данных int. Вернуть массив именно int можно, если использовать Stream API, с которым задача решается в целом проще (при условии, если все числа в массиве действительно идут по возрастанию).
public static int[] getSubArrayBetween(int[] numbers, int start, int end) {
return IntStream.of(numbers)
.filter(integer -> integer >= start && integer <= end)
.toArray();
}
В вашем коде всё не так:
- Создаётся пустой массив, так как
k == 0в момент создания массива - Нестрогое сравнение индекса с длиной массива:
i <= numbers.lengthвызовет выход за пределы массиваArrayIndexOutOfBoundsExceptionпри обращении к элементам массиваnumbers[i] - Попытка обращения к элементам пустого массива
result[k]также вызоветArrayIndexOutOfBoundsException - Индекс
kне меняется, то есть все подходящие числа исходного массива пишутся в одну ячейку.
Исправление указанных ошибок не является целью данного ответа.
Самое простое/лаконичное решение -- с использованием Stream API, показанное в ответе Byb:
public static int[] getSubArrayBetween(int[] numbers, int start, int end) {
return IntStream.of(numbers).filter(n -> start <= n && n <= end).toArray();
}
Для более классического решения, без использования коллекций, следует найти минимальный и максимальный индексы элементов входного массива. Если такие индексы не существуют, вернуть пустой массив, иначе копию массива между найденными индексами при помощи Arrays.copyOfRange:
public static int[] getSubArrayBetween(int[] numbers, int start, int end) {
if (numbers == null || numbers.length == 0 || numbers[0] > end || numbers[numbers.length - 1] < start) {
return new int[0];
}
int min = 0;
while (numbers[min] < start) min++;
int max = arr.length - 1;
while (numbers[max] > end) max--;
return Arrays.copyOfRange(numbers, min, max + 1);
}