如何展平数组并摆脱空?

时间:2016-04-04 22:00:56

标签: java arrays object arraylist null

我试图采用任意深度嵌套的数组并展平数组,以及摆脱数组中的任何空对象。

例如,我希望能够输入一个嵌套数组 [1, 5, [[6, 4], 91, 12, null, [[null]]], -2] 并返回一个没有任何空值的一维数组。我该如何解决这个问题?

我在下面提供了我的解决方案,但我一直在

  

我无法转换为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;
 }

2 个答案:

答案 0 :(得分:6)

使用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();
}

要考虑的第一点是int[]不是Object[]。因此,此方法接受Object[]来表示它可以被赋予任何类型的至少具有2维的整数数组,即int[][],直到任意数量的维度。它使用Objects::nonNull谓词过滤掉空元素。

然后神奇的事情发生了:由Stream<Object>返回的Arrays.stream(array)平面映射到IntStream:如果其中的元素是Object[],则意味着我们仍然有超过2个维度,并且该方法是递归调用自身的。另一方面,如果我们有一个int[]的实例,那么我们可以用它的Stream替换它。

调用代码示例:

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

当然,此方法不接受int[],这可能是没有什么可以展平的情况(并且由于int不能null而无需过滤。)

答案 1 :(得分:2)

最简单的(但不是最快的必要)解决方案之一可能是:

  • 生成代表你的数组的字符串(Arrays.deepToString在这里很有用),比如

    "[null, [4, 5, 6], [3, 1, 10], [4, 2, 9], null, null]"
    
  • 从中移除[ ] ,

  • 等字符
  • 拆分空格
  • 迭代接收到的数组
    • 过滤所有&#34; null&#34;字符串
    • 将非空字符串转换为您选择的数字类型,并将其添加到结果列表中。

简而言之,您的解决方案可能看起来像(我假设您可以使用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());
}

如果你想分割浮点数并且你的语言环境也使用,作为十进制标记1,25,你需要决定我们应该删除哪个,以及{{1}是数字的一部分,应该留下来。对于这种情况,解决方案可能是删除,之后的空格(但我们不想删除该空格,因为我们需要,)。由于split正在使用正则表达式,我们可以使用先行replaceAll机制,这将允许我们在当前匹配后测试部分,但不包括匹配中的测试部分。

因此我们需要(?=...),这将确保已移除的replaceAll("\\[|\\]|,(?=\\s)","")后面必须有空格,但不会删除该空格。