Java 如何将列表连接到一个列表中

Java 如何将列表连接到一个列表中,java,arraylist,concatenation,Java,Arraylist,Concatenation,我有一个值列表,其中一些可以是列表/集合或单个值。在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

我有一个值列表,其中一些可以是列表/集合或单个值。在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);
          }
        }

     }
ArrayList concatenated=new ArrayList();
用于(电视:输入){
试一试{
concatenated.addAll((Collection)v);
}
捕获(异常e1){
试一试{
concatenated.addAll((List)v);
}
捕获(异常e2){
连接。添加(v);
}
}
}
但那个密码对我来说太可怕了。首先,我不知道尝试强制转换到列表或集合是否足够-是否有其他类型我应该尝试强制转换到?有什么我不应该忽视的错误吗


如何做到这一点?

使用
异常来控制应用程序流/业务逻辑是一种反模式。你可以阅读更多关于它的信息,还有


在集合中存储不同类型的元素可能很难调试和维护。您可以编写自己的包装器,并从使用中封装对其的处理。您可以参考灵感。

除非列表中有
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;
} 
//编辑:因为输入'Collection'的类型没有严格绑定
列表展平(集合输入){
串联列表=新的ArrayList();
用于(对象v:输入){
if(v instanceof Collection){
addAll(展平((集合)v));
}否则{
连接。添加(v);
}
}
返回连接;
} 
在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]
jshell>List List=List.of(1,2,List.of(3,4),List.of(5,6),7)
列表==>[1,2,3,4,5,6,7]
jshell>展平(列表)
$3 ==> [1, 2, 3, 4, 5, 6, 7]

正如其他人所提到的,对控制流使用异常并不理想。您可以改为使用
instanceof
操作符来测试元素是否为
集合
。这个例子很好地说明了这一点。如果您想要更通用的选项,还可以执行以下操作:

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;
}
给我:

[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]

请注意,字母是按顺序排列的,因为
List
s和数组具有保证的迭代顺序。如果您的
Iterable
包含一个
Set
deepflant
的结果每次的顺序可能不一样。

fyi Java不支持列表中的混合匹配类型,就像您在
input
中一样,它可能类似于
input=[1]、[2]、[3,4]、[5,6]、[7]
可能有
null
值(异常处理是为了其他目的)?我想你可以这样做
concatenated.addAll((Iterable)v)
而不是尝试强制转换到
集合
列表
@MrCholo数组列表不具有
addAll
Iterable
的重载。您可以使用的最简单界面是
Collection
。原因是,
Iterable
不必保存数据。它可以是一次读取,甚至可以是随机返回的数据。它所指定的只是你可以在上面迭代。这种类型的列表操作通常被称为“展平”。是的,但是集合呢?你能在Iterable上使用instanceof吗?集合和列表都实现了Iterable,因此work@MrCholo
null
instanceof
的有效参数。它总是返回false。而
ArrayList
可以接受
null
作为
add
的输入。我认为对该解决方案的一个很好的补充是使其递归。ie
concatenated.addAll(concatenateList((List)v))
通过这种方式,您可以处理多级嵌套。此方法的更好名称可能是
flatte
@MrCholo
List
extends
Collection
@nullpointer这是一个有趣的问题!我曾经尝试过解决这个问题(在处理检查JSON数据时,没有提前准备模式),我认为Java没有一个好的模型来处理这个问题。根本问题是,当专门化容器时,基本的
集合
列表
映射
接口不考虑嵌套的数据层次结构。其他语言处理这个问题的方式不同,比如通过使用模式匹配而不是严格的类匹配。解决这个问题的一个很好的例子是Python的新型提示系统。
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);