Способ Перегрузки Технических средств

#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:

Ну, я думаю, что вокруг есть несколько очень интересных проблем, все вместе взятых. Именно

  1. Как обобщить обработку массива и объявление метода для произвольной глубины (это ваш первоначальный вопрос)?
  2. Как глубоко пересечь массив с неизвестной глубиной?
  3. Как ввести некоторую полезную нагрузку в обход массива (в вашем случае — подсчет нечетных чисел) независимо от самого обхода?
  4. Можно ли обобщить подход для массивов примитивов и объектов и как это сделать?

У меня есть хорошее предложение по пунктам 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();