简体   繁体   English

如何扁平化数组并摆脱null?

[英]How to flatten an array and get rid of null?

I am trying to take an arbitrarily deep-nested array and flatten the array, as well as get rid of any null objects in the array. 我试图获取一个任意深度嵌套的数组并展平该数组,并摆脱该数组中的任何空对象。

For example I want to be able to input a nested array like [1, 5, [[6, 4], 91, 12, null, [[null]]], -2] and return a one-dimensional array without any null values. 例如,我希望能够输入一个嵌套数组,例如[1, 5, [[6, 4], 91, 12, null, [[null]]], -2]然后返回一维数组而没有任何空值。 How would I go about solving this? 我将如何解决这个问题?

I provided my solution below, but I keep getting an 我在下面提供了解决方案,但我不断得到

I cannot be cast to java.lang.Integer error. 我无法转换为java.lang.Integer错误。

public static void main(String[] args) {
    int[][] numbers = {null, {4, 5, 6},{3, 1, 10}, {4, 2, 9}, null, null};
    flatten(numbers);
}

public static ArrayList<Integer> flatten(Object[] nestedNumbers) {
    if (nestedNumbers == null) return null;
    ArrayList<Integer> flattenedNumbers = new ArrayList<>();
    for (Object element : nestedNumbers) {
        if (element != null) {
            flattenedNumbers.add((Integer)element);
        } 
    }
    return flattenedNumbers;
 }

A possible solution using the Stream API introduced in Java 8 is the following: 使用Java 8中引入的Stream API的可能解决方案如下:

public static int[] flatten(Object[] array) {
    return Arrays.stream(array)
                 .filter(Objects::nonNull)
                 .flatMapToInt(a -> {
                    if (a instanceof Object[]) return Arrays.stream(flatten((Object[]) a));
                    return Arrays.stream((int[]) a);
                 })
                 .toArray();
}

The first point to consider is that an int[] is not an Object[] . 要考虑的第一点是int[]不是Object[] So, this method accepts a Object[] to represent that it can be given any type of integer array with at least 2 dimensions, ie int[][] , up to any number of dimensions. 因此,此方法接受一个Object[]来表示可以为它提供至少2个维的任意类型的整数数组,即int[][] ,最多不限维数。 It filters out null elements, with the Objects::nonNull predicate. 它使用Objects::nonNull谓词过滤掉空元素。

Then the magic happens: the Stream<Object> , returned by Arrays.stream(array) , is flat mapped to an IntStream : if the elements inside it are Object[] , then it means that we still have more than 2 dimensions, and the method is recursively calling itself. 然后神奇的事情发生了:由Arrays.stream(array)返回的Stream<Object>被平面映射到IntStream :如果其中的元素是Object[] ,则意味着我们仍然有两个以上的维度,并且该方法是递归调用自身。 On the other hand, if we have an instance of int[] , then we can just replace it with a Stream of that. 另一方面,如果我们有int[]的实例,那么我们可以用它的Stream代替它。

Example calling code: 调用代码示例:

public static void main(String[] args) {
    int[][][] numbers = {null, {{4}, {5}, {6,1}},{{3,2}, {1}, {10}}, {{4,1}, {2,3}, {9,8}}, null, null};
    int[] flat = flatten(numbers);
    System.out.println(Arrays.toString(flat));
}

Of course, this method doesn't accept int[] , which would be the case where is nothing to flatten (and nothing to filter since int can't be null ). 当然,此方法不接受int[] ,在这种情况下,没有什么要扁平化(也没有要过滤的东西,因为int不能为null )。

One of simplest (but not necessary fastest) solution could be to: 一种最简单 (但不是必需最快)的解决方案是:

  • generate string which will represent your array ( Arrays.deepToString can be helpful here) like 生成将代表您的数组的字符串( Arrays.deepToString在这里可能会有所帮助),例如

     "[null, [4, 5, 6], [3, 1, 10], [4, 2, 9], null, null]" 
  • remove from it characters like [ ] , 从它的人物,如除去[ ] ,

  • split on spaces 在空格上分割
  • iterate over received array to 遍历接收到的数组
    • filter all "null" strings 过滤所有“空”字符串
    • convert non-null strings to numeric type of your choice and add it to result list. 将非空字符串转换为您选择的数字类型,并将其添加到结果列表。

In short your solution could look like (I am assuming you are allowed to use Java 8) 简而言之,您的解决方案可能看起来像(我假设您被允许使用Java 8)

public static List<Integer> flatten(Object[] nestedNumbers) {
    String text = Arrays.deepToString(nestedNumbers);
    System.out.println(text);
    return Stream.of(text.replaceAll("\\[|\\]|,", "").split("\\s+"))
        .filter(s->!s.equals("null"))
        .map(Integer::parseInt)
        .collect(Collectors.toList());
}

In case you want to split floating point numbers and your locale is also using , as decimal mark 1,25 you would need to decide which , we should remove and which , is part of number and should stay. 如果您想分割浮点数并且您的语言环境也使用,作为小数点1,25 ,则需要确定哪个,我们应该删除,哪个,是数字的一部分,应该保留。 For such case solution could be removing , which has space after it (but we don't want to remove that space because we need it in split ). 对于这种情况,解决方案可以是remove ,其后有空格(但是我们不想删除该空间,因为我们需要split )。 Since replaceAll is using regex we can use look-ahead (?=...) mechanism which will allow us to test part after current match, but not include that tested part in match. 由于replaceAll使用的是正则表达式,因此我们可以使用replaceAll (?=...)机制,该机制将允许我们在当前匹配之后测试零件,但不将该匹配的零件包括在匹配中。

So we would need to replaceAll("\\\\[|\\\\]|,(?=\\\\s)","") which will ensure that removed , must have space after it, but will not remove that space. 因此,我们需要replaceAll("\\\\[|\\\\]|,(?=\\\\s)","")这将确保删除,之后它必须有空间,但不会删除空间。

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

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