#java #arrays #multidimensional-array
Вопрос:
У меня есть перегрузка метода, которая заключается в следующем:
public class Odddetector {
public static void main(String[] args) {
int count = countOdd(new int [] {5, 7, 3, 9, 0});
System.out.println(count);
count = countOdd(new int [] {2, 6, 4, 8, 1});
System.out.println(count);
count = countOdd(5, 7, 10);
System.out.println(count);
count = countOdd(8, 2, 7);
System.out.println(count);
count = countOdd(new int[][] {{1, 2}, {3, 4, 5}});//extra point only
System.out.println(count);
count = countOdd(new int[][] {{6, 2}, {3, 4, 0}});//extra point only
System.out.println(count);
}
public static int countOdd(int[] a){
int count=0;
for (int i: a) count = (i %2 != 0)? count:count;
return count;
// Do Something;
}
public static int countOdd(int[][] a){
// Do Something;
int count=0;
for (int b = 0; b< a.length; b ){
//System.out.println(java.util.Arrays.toString(a[b])); not a necessary line.
count = countOdd(a[b]);
}
return count;
}
// more method overloading
Мой вопрос заключается в том, есть ли способ свести решение к одному методу, учитывающему N-мерные массивы. Код работает нормально, как это, однако я хотел бы знать, какие методы Java могут помочь объяснить увеличение размеров. Я хотел бы добавить некоторые детали, и это то, что первый метод является базовым методом, а все остальные методы вызывают этот первый int[] a. Новый раздел, который я добавил, — это полный код, который я в настоящее время разрабатываю, и который мой профессор дал в качестве задачи. В настоящее время у меня есть Структуры данных Ланга, и я могу принимать подсказки. Я предпочитаю подсказки на самом деле, потому что я хотел бы научиться кодировать это.
Комментарии:
1. Я думаю, это будет зависеть от того, что
// Do Something;
на самом деле происходит.2. Хорошо, конечно, я добавлю это
3. @JohnnyMopp он строится из этого первого метода и смотрит только на массив 1D и считает нечетные числа, моя проблема в том, что я хочу найти способ сократить постоянный вызов метода.
4. Я попытался придумать рекурсивный метод, но не смог перегрузить метод varargs, поэтому мне пришлось назвать его как-то по-другому. Сейчас время обеда… Но вы можете проверить это здесь: ideone.com/5uf77A Может быть, это подтолкнет вас в правильном направлении.
5. @JohnnyMopp, ваша попытка должна быть опубликована в качестве ответа. Незначительное улучшение: может иметь смысл добавить проверку класса
if (a[0] instanceof Number)
, затем привестиi
кNumber
и использовать егоNumber::intValue
метод при проверке на странность вместо приведения кint
.
Ответ №1:
Когда параметром является многомерный массив, вы можете рекурсивно вызвать функцию, которая копает вниз, пока не получите 1d массив чисел. Логика такова:
if a is a multi-dimensional array
for each array in a
call recursively
else
count odd numbers in a
У меня есть 2 функции. Тот, который принимает переменное число аргументов, и рекурсивный. Первый просто вызывает второй с аргументами var в виде массива. Функция varargs нуждается в небольшой работе, если вы хотите разрешить смешанные параметры (например: countOdd(new int [] {1,2,3}, 4, 5);
)
// The var args version. You call this. It then calls the recursive
// version.
public static <T> int countOdd(T... arguments)
{
return countOddRec(arguments);
}
// Recursive version
private static <T> int countOddRec(T[] a)
{
if (a == null || a.length == 0) return 0;
int count=0;
// Is it an array of Numbers?
if (a[0] instanceof Number) {
for (T i: a) {
// Simplified the counting code a bit. Any # mod 2 is either 0 or 1
count = ((Number)i).intValue() % 2;
}
}
// Is it an multi-dimensional? Call recursively for each sub-array.
else {
for (T sub : a) {
count = countOddRec((T[])sub);
}
}
return count;
}
Как упоминалось в комментариях, это не будет работать для примитивных типов данных (например: int
и т. Д.). Вместо этого используйте непримитивные типы (например: Integer
и т. Д.).
Комментарии:
1. Однако это не сработает для примитивов
2. @Василиясковский Да, это верно.
3. Я усомнился в этом и проверил. Это не работает — приведение к
T[]
(ближе к концу метода) завершается неудачно для вложенного массива, потому что параметрT
может быть толькоObject
и после удаления будет чистое приведение кObject[]
, ноint[]
не является экземпляромObject[]
4. @Василиясковский Да, я согласен с вами, что это не будет работать с примитивными типами. Преобразование всего в
Integer
действительно работает: ideone.com/VJh8Ox
Ответ №2:
Ну, я думаю, что вокруг есть несколько очень интересных проблем, все вместе взятых. Именно
- Как обобщить обработку массива и объявление метода для произвольной глубины (это ваш первоначальный вопрос)?
- Как глубоко пересечь массив с неизвестной глубиной?
- Как ввести некоторую полезную нагрузку в обход массива (в вашем случае — подсчет нечетных чисел) независимо от самого обхода?
- Можно ли обобщить подход для массивов примитивов и объектов и как это сделать?
У меня есть хорошее предложение по пунктам 3: вместо жесткого кодирования полезной нагрузки в самом методе мы можем создать IntStream
(или универсальный Stream
для Object
версии), который может быть обработан отдельно.
По пунктам 1 и 4 я предполагаю, что это, вероятно, невозможно или, по крайней мере, не элегантно. java.lang.reflect.Array
в этом нет ничего удивительного, и я предполагаю, что если JDK не смог этого сделать, я тоже не могу. Таким образом, лучшим вариантом, вероятно, будет разрешить общую подпись Object
с несколькими часто используемыми перегрузками, вплоть до глубины 3. Конечно, это подразумевает опасность ClassCastExceptions
во время выполнения.
Итак, конечный результат при выполнении пункта 2 может выглядеть следующим образом
public class FlattenArray {
public static IntStream flatten(int n) {
return IntStream.of(n);
}
public static IntStream flatten(int[] array) {
return IntStream.of(array);
}
public static IntStream flatten(int[][] array) {
return flatten((Object) array);
}
public static IntStream flatten(Object array) {
Class<?> aClass = array.getClass();
if (!aClass.isArray())
return IntStream.of(((Number) array).intValue());
else {
Class<?> componentType = aClass.getComponentType();
if (componentType.isPrimitive())
return IntStream.of((int[]) array);
else
return Arrays.stream((Object[]) array).flatMapToInt(FlattenArray::flatten);
}
}
}
И используйте это как
long count = FlattenArray.flatten(2, 3, 5, 7).filter(i -> i amp; 1 != 0).count();