【问题标题】:Flatten nested arrays in java在java中展平嵌套数组
【发布时间】:2015-10-29 08:28:23
【问题描述】:

我想展平嵌套数组,例如:

[[[1],2],[3]],4] -> [1,2,3,4] 

在java中手动我找不到线索! :S

我尝试了手动 java 脚本指南,但没有得到解决方案

【问题讨论】:

  • 这是一个javascript问题。这在 Java 中没有意义。
  • 我想用任何语言解决它,java或javascript
  • 我们真的很想提供帮助,但我不明白您的要求。 cn 你给输入和期望的输出一个Java例子?
  • 但是解决这个问题的方法在 Java 中与在 JavaScript 中完全不同......
  • Java 没有混合类型的数组(其中项目可以是 int 或 int[])。虽然它有 List 对象...

标签: java arrays algorithm


【解决方案1】:

你可以试试这个代码:

String a = "[[[1],2],[3]],4] ";
a= a.replaceAll("[(\\[|\\])]", "");
String[] b = a.split(",");

【讨论】:

  • OP 有数组,而不是字符串,你返回的是字符串而不是数组。
【解决方案2】:

我用Java创建了a class to solve this,代码也如下所示。

解决方案:

package com.conorgriffin.flattener;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Flattens an array of arbitrarily nested arrays of integers into a flat array of integers.
 * <p/>
 * @author conorgriffin
 */
public class IntegerArrayFlattener {

    /**
     * Flatten an array of arbitrarily nested arrays of integers into a flat array of integers. e.g. [[1,2,[3]],4] -> [1,2,3,4].
     *
     * @param inputArray an array of Integers or nested arrays of Integers
     * @return flattened array of Integers or null if input is null
     * @throws IllegalArgumentException
     */
    public static Integer[] flatten(Object[] inputArray) throws IllegalArgumentException {

        if (inputArray == null) return null;

        List<Integer> flatList = new ArrayList<Integer>();

        for (Object element : inputArray) {
            if (element instanceof Integer) {
                flatList.add((Integer) element);
            } else if (element instanceof Object[]) {
                flatList.addAll(Arrays.asList(flatten((Object[]) element)));
            } else {
                throw new IllegalArgumentException("Input must be an array of Integers or nested arrays of Integers");
            }
        }
        return flatList.toArray(new Integer[flatList.size()]);
    }
}

单元测试:

package com.conorgriffin.flattener;

import org.junit.Assert;
import org.junit.Test;

/**
 * Tests IntegerArrayFlattener
 */
public class IntegerArrayFlattenerTest {

    Integer[] expectedArray = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    @Test
    public void testNullReturnsNull() throws IllegalArgumentException {
        Assert.assertNull(
                "Testing a null argument",
                IntegerArrayFlattener.flatten(null)
        );
    }

    @Test
    public void testEmptyArray() throws IllegalArgumentException {
        Assert.assertArrayEquals(
                "Testing an empty array",
                new Integer[]{},
                IntegerArrayFlattener.flatten(new Object[]{})
        );
    }

    @Test
    public void testFlatArray() throws IllegalArgumentException {
        Assert.assertArrayEquals(
                "Testing a flat array",
                expectedArray,
                IntegerArrayFlattener.flatten(new Object[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
        );
    }

    @Test
    public void testNestedArray() throws IllegalArgumentException {
        Assert.assertArrayEquals(
                "Testing nested array",
                expectedArray,
                IntegerArrayFlattener.flatten(new Object[]{1, 2, 3, 4, new Object[]{5, 6, 7, 8}, 9, 10})
        );
    }

    @Test
    public void testMultipleNestedArrays() throws IllegalArgumentException {
        Assert.assertArrayEquals(
                "Testing multiple nested arrays",
                expectedArray,
                IntegerArrayFlattener.flatten(new Object[]{1, 2, new Object[]{3, 4, new Object[]{5}, 6, 7}, 8, 9, 10})
        );
    }

    @Test(expected = IllegalArgumentException.class)
    public void throwsExceptionForObjectInArray() throws IllegalArgumentException {
        IntegerArrayFlattener.flatten(
                new Object[]{new Object()}
        );
    }

    @Test(expected = IllegalArgumentException.class)
    public void throwsExceptionForObjectInNestedArray() throws IllegalArgumentException {
        IntegerArrayFlattener.flatten(
                new Object[]{1, 2, new Object[]{3, new Object()}}
        );
    }

    @Test(expected = IllegalArgumentException.class)
    public void throwsExceptionForNullInArray() throws IllegalArgumentException {
        IntegerArrayFlattener.flatten(
                new Object[]{null}
        );
    }

    @Test(expected = IllegalArgumentException.class)
    public void throwsExceptionForNullInNestedArray() throws IllegalArgumentException {
        IntegerArrayFlattener.flatten(
                new Object[]{1, 2, new Object[]{3, null}}
        );
    }

}

【讨论】:

    【解决方案3】:

    这就是我在 Java 中解决这个问题的方法:

    public class ArrayUtil {
    
        /**
         * Utility to flatten an array of arbitrarily nested arrays of integers into
         * a flat array of integers. e.g. [[1,2,[3]],4] -> [1,2,3,4]
         * @param inputList
         */
        public static Integer[] flattenArray(ArrayList<Object> inputList) {
    
            ArrayList<Integer> flatten = new ArrayList<Integer>();
            if (inputList.size() <= 0) {
                return new Integer[0];                          // if the inputList is empty, return an empty Integer[] array.
            }
    
            for (Object obj : inputList) {
                recursiveFlatten(flatten, obj);                 // otherwise we can recursively flatten the input list.
            }
    
            Integer [] flatArray = new Integer[flatten.size()];
            return flatArray = flatten.toArray(flatArray);      
        }
    
        /**
         * Recursively flatten a nested array.
         * @param flatten
         * @param o
         */
        private static void recursiveFlatten(ArrayList<Integer> flatten, Object o){
            if(isInteger(o)){                               // if the object is of type Integer, just add it into the list.
                flatten.add((Integer)o);
            } else if(o instanceof ArrayList){              // otherwise, we need to call to recursively flatten the array
                for(Object obj : (ArrayList<Object>) o){    // for the case where there are deeply nested arrays.
                    recursiveFlatten(flatten, obj);
                }
            }
        }
    
        /**
         * Return true if object belongs to Integer class,
         * else return false.
         * @param obj
         * @return
         */
        private static boolean isInteger(Object obj) {
            return obj instanceof Integer;
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      Java 8 的 Stream API 提供了一个紧凑而灵活的解决方案。使用方法

      private static Stream<Object> flatten(Object[] array) {
          return Arrays.stream(array)
                       .flatMap(o -> o instanceof Object[]? flatten((Object[])o): Stream.of(o));
      }
      

      您可以执行该操作

      Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10 };
      System.out.println("original: "+Arrays.deepToString(array));
      
      Object[] flat = flatten(array).toArray();
      System.out.println("flat:     "+Arrays.toString(flat));
      

      或者当您假设叶子对象是特定类型时:

      int[] flatInt = flatten(array).mapToInt(Integer.class::cast).toArray();
      System.out.println("flat int: "+Arrays.toString(flat));
      

      【讨论】:

      • 遗憾的是,如果内部数组是 int[] 这样的原始类型,这将不起作用,因为o instanceof Object[] 检查失败并且原始数组无法转换为对象数组。
      • @DQQpy 对于原始数组,不需要递归,因为原始数组不能包含数组,因此您可以使用.flatMap(o -&gt; o instanceof int[]? Arrays.stream((int[])o).boxed(): o instanceof Object[]? flatten((Object[])o): Stream.of(o));,或者,总是映射到int 值,public static IntStream flattenToInt(Object o) { return o instanceof int[]? Arrays.stream((int[])o): o instanceof Object[]? Arrays.stream((Object[])o) .flatMapToInt(x -&gt; flattenToInt(x)): IntStream.of(((Number)o).intValue()); }
      • 如果输入类型是像int[][][]这样的正则数组,操作会更简单,不需要递归,只需要n-1 @987654329 @ n 个维度的步骤,static IntStream flatten(int[][][] array) { return Arrays.stream(array).flatMap(Arrays::stream) .flatMapToInt(Arrays::stream); }
      • 好点,但是如果内部数组是混合类型的,那么所有大小写差异都会变得非常复杂。不过我找不到更好的解决方案
      • @DQQpy 你可以使用java.lang.reflect.Array 处理所有数组类型,如果你愿意的话:static Stream&lt;Object&gt; flatten(Object o) { return o != null &amp;&amp; o.getClass().isArray()? IntStream.range(0, Array.getLength(o)).mapToObj(ix -&gt; Array.get(o, ix)).flatMap(x -&gt; flatten(x)): Stream.of(o); }
      【解决方案5】:

      它可以通过迭代方法展平。

      static class ArrayHolder implements Iterator<Object> {
          private final Object[] elements;
          private int index = -1;
      
          public ArrayHolder(final Object[] elements) {
              this.elements = elements;
          }
      
          @Override
          public boolean hasNext() {
              return Objects.nonNull(elements) && ++index < elements.length;
          }
      
          @Override
          public Object next() {
              if (Objects.isNull(elements) || (index == -1 || index > elements.length))
                  throw new NoSuchElementException();
      
              return elements[index];
          }
      }
      
      
      private static boolean hasNext(ArrayHolder current) {
          return Objects.nonNull(current) && current.hasNext();
      }
      
      private void flat(Object[] elements, List<Object> flattened) {
          Deque<ArrayHolder> stack = new LinkedList<>();
          stack.push(new ArrayHolder(elements));
      
          ArrayHolder current = null;
          while (hasNext(current)
                  || (!stack.isEmpty() && hasNext(current = stack.pop()))) {
              Object element = current.next();
      
              if (Objects.nonNull(element) && element.getClass().isArray()) {
                  Object[] e = (Object[]) element;
                  stack.push(current);
                  stack.push(new ArrayHolder(e));
                  current = null;
              } else {
                  flattened.add(element);
              }
          }
      }
      

      您可以找到完整的源代码here 你可以使用递归来解决这个问题。

      private void flat(Object[] elements, List<Object> flattened) {
          for (Object element : elements)
          {
              if (Objects.nonNull(element) && element.getClass().isArray())
              {
                  flat((Object[])element, flattened);
              }
              else
              {
                  flattened.add(element);
              }
          }
      }
      

      这是recursion的链接。

      【讨论】:

        【解决方案6】:

        这就是我要解决的方法。 不知道你在寻找哪种效率。但是,是的。在 JavaScript 中完成这项工作。

        arr.toString().split(',').filter((item) =&gt; item).map((item) =&gt; Number(item))

        一种可能更有效的方法是使用 arr 和递归中的 reduce 和 concat 方法。

        function flattenDeep(arr1) {
           return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
        }
        

        【讨论】:

        • 你可以直接使用array.flat(Infinity),这样会更短。
        【解决方案7】:

        如果它是一个只有两层的原始数组,你可以这样做:

        Arrays.stream(array)
          .flatMapToInt(o -> Arrays.stream(o))
          .toArray()
        

        获取对应的装箱数组(必要时可以拆箱)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-28
          • 1970-01-01
          • 1970-01-01
          • 2012-10-31
          • 2017-03-06
          • 2017-07-20
          • 2017-12-26
          • 2013-11-06
          相关资源
          最近更新 更多