简体   繁体   English

扁平化泛型数组的方法

[英]Method to flatten generic array

I've been trying to write a method that will flatten a generic array if it is nested.我一直在尝试编写一个方法,如果它是嵌套的,它将展平一个通用数组。

    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;
    }

This code does not cause any errors but also does not work.此代码不会导致任何错误,但也不起作用。 When e is not an array, things work as expected... a list is populated with the elements of in and returned.e不是数组时,事情按预期工作……一个列表填充了in的元素并返回。

However when e.getClass().isArray() == true , the elements of e are not added.但是,当e.getClass().isArray() == true ,不会添加e的元素。 Rather the original array is added so I end up with a list of arrays.而是添加了原始数组,所以我最终得到了一个数组列表。

My use case here is that I have a method that is being passed generics T[] someArray我的用例是我有一个方法正在传递泛型T[] someArray

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

The input someArray may either be nested or not (ie T itself may be an array, resulting in T[][] ).输入someArray可以嵌套也可以不嵌套(即T本身可能是一个数组,导致T[][] )。 I want to determine the unique elements contained in the input, whether or not it is nested.我想确定输入中包含的唯一元素,是否嵌套。 Passing the input someArray to a set only works if it's not nested, hence I'm trying to flatten.将输入someArray传递给一个集合只在它没有嵌套时才有效,因此我试图变平。

So my question is, how can I do this and why is my method above not working?所以我的问题是,我该怎么做,为什么我上面的方法不起作用? Thanks in advance for the edcuation.在此先感谢您的教育。

Your code can't work.你的代码不能用。 The generics just don't line up.泛型只是不排队。

Let's say you have an array that is a combination of strings and arrays of strings.假设您有一个由字符串和字符串数组组合而成的数组。 That cannot possibly be a T[] unless T is object, which isn't what you want (as that would mean you get a List<Object> . After all, If T is String , then your input array, which is defined as T[] in , is a String[] in , which cannot contain string arrays . After all, a String[] is not a subtype of String , for obvious reasons.那不可能是T[]除非 T 是对象,这不是你想要的(因为这意味着你得到一个List<Object> 。毕竟,如果TString ,那么你的输入数组,它被定义为T[] in ,是一个String[] in不能包含字符串数组。毕竟,一个String[]不是String的子类型,原因显而易见。

It is impossible to describe in terms of generics the concept of 'an array of Strings, or an array of arrays of Strings, or an array of arrays of arrays of Strings, and so forth'.不可能用泛型来描述“字符串数组,或字符串数​​组的数组,或字符串数​​组的数组,等等”的概念。 So, generics have no place here.所以,泛型在这里没有立足之地。 If you want that, all you can 'type' is 'an array whose component type is unknown and hybrid anyway', which is Object[] in java (this is co/contra-variance wise broken, but this is just part of the java spec: Variance on arrays is incorrect, known problem and not fixable).如果你想要那个,你可以“输入”的只是“一个组件类型未知且混合的数组”,它是 Java 中的Object[] (这是协方差/逆方差问题,但这只是一部分java 规范:数组的方差不正确,已知问题且无法修复)。

This gets you a secondary issue: Generics are erased, and in that model you don't have an actual type to work with.这给你带来了一个次要问题:泛型被删除了,在那个模型中你没有一个实际的类型可以使用。 In fact, because it is impossible to use generics to tell the compiler to do some type checking on the input array, there is nothing the compiler can do for you, so any type checking you want (and you clearly want that, you don't want to return a List of who knows what this is ), will have to be done at runtime.事实上,因为不可能使用泛型告诉编译器对输入数组进行一些类型检查,所以编译器无法为您做任何类型检查(而且您显然希望这样做,您不需要) t 想返回一个List of who knows what this isList of who knows what this is ),必须在运行时完成。

Unfortunately, it is impossible to do that, too - you can't check if at runtime if some object is, say, a Map<String, Integer> .不幸的是,这也是不可能的——你不能在运行时检查某个对象是否是Map<String, Integer>

So, what you want is impossible.所以,你想要的是不可能的。

It becomes possible if you're okay with this method being only able to do the job for reified types.如果您对这种方法只能为具体化类型完成这项工作感到满意,则有可能。 That is, types that don't contain any <> themselves.也就是说,类型本身不包含任何<> So, if you want to take 'an array that contains a combination of "Map of string to integer" and "arrays of Maps of string to integer"', this method will not be able to do that and it is in fact completely impossible to do such a thing in java.所以,如果你想取'一个包含“字符串到整数映射”和“字符串到整数映射的数组”组合的数组',这个方法将无法做到这一点,实际上是完全不可能的在java中做这样的事情。 But if you're okay with, say, "An array containing a combination of strings and arrays of strings" and want to turn that into a flattened-out list of strings, okay, that's possible.但是,如果您对“包含字符串和字符串数组的组合的数组”感到满意,并且想将其转换为扁平的字符串列表,那是可能的。

It's complicated, though:不过很复杂:

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));
        }
    }
}

In action:在行动:

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);

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM