Как объединить списки в один список - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть список значений, некоторые из которых могут быть списками / коллекциями или отдельными значениями.В нотации JavaScript это может выглядеть так:

const input = [1,2,[3,4], [5,6], 7];

, и я хочу получить:

const concatenated = [1,2,3,4,5,6,7];

Итак, у меня есть этот код Java:

      ArrayList<T> concatenated = new ArrayList<>();

      for (T v : input) {
        try{
          concatenated.addAll((Collection) v);
        }
        catch (Exception e1){
          try{
            concatenated.addAll((List) v);
          }
          catch (Exception e2){
            concatenated.add(v);
          }
        }

     }

, но этоКод кажется мне довольно ужасным.Во-первых, я не знаю, достаточно ли попытки приведения к списку или коллекции - есть ли другие типы, на которые я должен попытаться привести?Есть ли ошибки, которые я не должен игнорировать?

Как это сделать правильно?

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

Код не нуждается в обработке Exception как таковой, если в списках нет значений null.Хотя в вашем случае должно быть достаточно просто привести основание к instanceOf как:

// Edit: Since the type of the input `Collection` is not bound strictly
List<Object> flatten(Collection<?> input) {
    List<Object> concatenated = new ArrayList<>();
    for (Object v : input) {
        if (v instanceof Collection) {
            concatenated.addAll(flatten((Collection<?>) v));
        } else {
            concatenated.add(v);
        }
    }
    return concatenated;
} 

, используя его в дальнейшем на jshell, и вы получите:

jshell> List<Object> list = List.of(1,2,List.of(3,4),List.of(5,6),7) 
list ==> [1, 2, [3, 4], [5, 6], 7]

jshell> flatten(list)
$3 ==> [1, 2, 3, 4, 5, 6, 7]

:

0 голосов
/ 11 февраля 2019

Как уже упоминалось, использование исключений для потока управления не является идеальным.Вместо этого вы можете использовать оператор instanceof, чтобы проверить, является ли элемент Collection.Ответ от nullpointer показывает хороший пример этого.Если вам нужен более общий вариант, вы также можете сделать что-то вроде:

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public static <E> List<E> deepFlatten(final Iterable<?> iterable, final Class<E> type) {
    if (type.isPrimitive() || type.isArray() || Iterable.class.isAssignableFrom(type)) {
        throw new IllegalArgumentException(
                "type must not denote a primitive, array, or java.lang.Iterable type: " + type);
    }
    final List<E> result = new ArrayList<>();
    for (final Object element : iterable) {

        if (element instanceof Iterable<?>) {
            result.addAll(deepFlatten((Iterable<?>) element, type)); // recursion

        } else if (element != null && element.getClass().isArray()) {

            if (element instanceof Object[]) {
                result.addAll(deepFlatten(Arrays.asList((Object[]) element), type)); // recursion
            } else { // primitive array
                final Iterable<?> itrArray = IntStream.range(0, Array.getLength(element))
                        .mapToObj(index -> Array.get(element, index))::iterator; // method reference
                result.addAll(deepFlatten(itrArray, type)); // recursion
            }

        } else {
            /*
             * Will throw ClassCastException if any element is not an instance
             * of "type". You could also throw a NullPointerException here if
             * you don't want to allow null elements.
             */
            result.add(type.cast(element));
        }

    }
    return result;
}

Это также обрабатывает "встроенные" массивы, а также Iterable s, через рекурсию.Обратите внимание, что он не обрабатывает Map с из-за неоднозначности;мы должны сгладить ключи или значения - или оба?

Вызов выше с помощью:

Iterable<?> iterable = List.of(
        "A", "B", "C", "D",
        List.of("E", "F", List.of("G", "H"), "I", "J"),
        "K",
        new String[]{"L", "M", "N", "O", "P"},
        new String[][]{{"Q", "R"}, {"S", "T"}, {"U"}, {"V"}},
        new Object[]{"W", "X"},
        "Y", "Z"
);
List<String> flattened = deepFlatten(iterable, String.class);
System.out.println(flattened);

Дали мне:

[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]

Обратите внимание, что буквы вorder, потому что List s и массивы имеют гарантированные итерационные порядки.Если ваш Iterable содержал Set, то результат deepFlatten может быть не в том же порядке каждый раз.

0 голосов
/ 11 февраля 2019

Использование Exceptions для управления потоком приложений / бизнес-логикой является анти-паттерном.Вы можете прочитать больше об этом здесь , здесь и здесь .

Относительно хранения различных типов элементов в коллекциях может быть сложно отлаживать и поддерживать.Вы можете написать свою собственную обертку и инкапсулировать обработку из использования.Вы можете обратиться этот для вдохновения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...