java - 展平通用数组的方法

标签 java arrays list generics set

我一直在尝试编写一种方法,该方法可以在嵌套时将通用数组展平。

    private static <T> List<T> flatten(T[] in) {
        List<T> result = new ArrayList<>();
        for (T e : in) {
            if (e.getClass().isArray()) {
                result.addAll(Arrays.asList(e)); ## Issue is here. 
            } else {
                result.add(e);
            }
        }
        return result;
    }

此代码不会导致任何错误,但也不起作用。当 e 不是数组时,事情会按预期工作...列表中会填充 in 的元素并返回。

但是,当e.getClass().isArray() == true时,e的元素不会被添加。相反,添加了原始数组,因此我最终得到了一个数组列表。

我的用例是我有一个正在传递泛型的方法 T[] someArray

public <T> void doSomeStuff(T[] someArray) {
   Set<T> unique = Sets.newHashSet(someArray)
   ... do some stuff with the unique values ... 
}

输入 someArray 可以嵌套也可以不嵌套(即 T 本身可能是一个数组,导致 T[][]) 。我想确定输入中包含的唯一元素,无论它是否嵌套。将输入 someArray 传递给一组仅在未嵌套的情况下才有效,因此我试图展平。

所以我的问题是,我该如何做到这一点以及为什么我上面的方法不起作用?预先感谢您的教育。

最佳答案

您的代码无法运行。泛型就是不对齐。

假设您有一个由字符串和字符串数组组合而成的数组。 这不可能是 T[] 除非 T 是对象,这不是您想要的(因为这意味着您得到 List<Object> 。毕竟,如果 TString ,那么您的输入数组是定义为 T[] in ,是一个 String[] in ,它不能包含字符串数组。毕竟,出于显而易见的原因, String[] 不是 String 的子类型。

不可能用泛型来描述“字符串数组,或字符串数​​组的数组,或字符串数​​组的数组的数组,等等”的概念。所以,泛型在这里没有地位。如果你想要这样,你可以“输入”的是“一个组件类型未知且混合的数组”,在java中是Object[](这是co/contra-variance明智的破坏,但这只是java规范的一部分:数组的方差不正确,已知问题且无法修复)。

这会给您带来第二个问题:泛型被删除,并且在该模型中您没有可以使用的实际类型。事实上,因为不可能使用泛型来告诉编译器对输入数组进行一些类型检查,所以编译器无法为您做任何事情,因此您想要的任何类型检查(并且您显然想要这样,您不这样做)不想返回 List of who knows what this is ),必须在运行时完成。

不幸的是,这也是不可能的 - 你无法在运行时检查某个对象是否是 Map<String, Integer>

所以,你想要的东西是不可能的。

如果您同意此方法只能完成具体类型的工作,那么这是可能的。也就是说,类型本身不包含任何 <>。因此,如果您想获取“包含“字符串到整数的映射”和“字符串到整数的映射数组”组合的数组”,此方法将无法做到这一点,而且实际上是完全不可能的在java中做这样的事情。但是,如果您同意“包含字符串和字符串数组的组合的数组”,并希望将其转换为扁平化的字符串列表,那么这是可能的。

但是这很复杂:

public <T> List<T> flattenArray(Class<T> type, Object[] in) {
    if (type.isArray()) throw new IllegalArgumentException();
    var out = new ArrayList<T>();
    flattenArray0(type, in, out);
    return out;
}

private <T> void flattenArray0(Class<T> type, Object[] in, List<T> out) {
    for (Object a : in) {
        if (a == null) {
            out.add(null);
        } else if (a.getClass().isArray()) {
            flattenArray0(type, (Object[]) a, out);
        } else {
            out.add(type.cast(a));
        }
    }
}

实际操作:

Object[] test = new Object[3];
test[0] = "Hello";
test[1] = new String[] {"Foo", "Bar"};
Object[] threeDeep = new Object[2];
test[2] = threeDeep;
threeDeep[0] = "Goodbye";
threeDeep[1] = new String[] {"Baz"};

List<String> result = flattenArray(String.class, test);
System.out.println(result);

应该打印:["Hello", "Foo", "Bar", "Goodbye", "Baz"]

关于java - 展平通用数组的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68423209/

相关文章:

java - 安卓快速连接/协议(protocol)

arrays - 创建 int 数组,它是一个位字段

c# - 如何遍历包含一个字典的字典,该字典包含另一个包含列表的字典

python 列表控制增量

java - 将数组保存在 Vector 中并再次取出

Java 数组拆分和重新连接。丢失的元素

Java以点开头的多个函数

c++ - 处理数组访问时可能会生成不一致的代码

c++ - STL vector 与数组

java - 如何使用 Singleton 类将列表数据从一个 fragment 传递到另一个 fragment ?