用Java实现的Ruby的flatten()方法算法

时间:2015-01-06 22:35:27

标签: java arrays algorithm object

我正在阅读一本Ruby书,并遇到了一个函数.flatten。顾名思义,它会像下面那样展平数组:

a = [ 1, 2, 3 ]           #=> [1, 2, 3]
b = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
c = [ a, b, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
c.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

我的问题是我正在尝试实现看看我是否可以在Java中提出一种算法,这样当传递一个数组(可能包含)其他数组时,它将返回一个数组。我不知道是否有更简单的方法可以做到这一点,或者可能已经在Java中实现了它。无论如何,我知道我今天没有等我的时间给它开枪:)

以下是我的算法:     创建一个arrayList。

 for each element in array as x, 
   if x element, add to arrayList
else
  do a recurse(pass x as arg)

  Once done, create a int array with size = arrayList.
  Loop arrayList and add each element 

到目前为止,这是我的代码:

public class Flatten {

public static void main(String[] args){
   a = [ 1, 2, 3 ]          
   b = [ 4, 5, 6, [7, 8] ] 
   c = [ a, b, 9, 10 ]       
   flatten(c);                 
}

public static int[] flatten(int[] a){
    ArrayList<Integer> ar = new ArrayList<Integer>();

    for(int i=0; i<a.; i
      Object o = a[i];  
        if(!obj instanceof Object[])){
          arr.add(a[i]);
   }

   else {
     int[] newArray = nR
      flatten(nR);
        }
     }     
  }

  int[] results = new int[ar.size()];

  for(int i=0; i<ar.size(); i++){
     int x = ar.get(i);
     int[i] = x;
  }

     return results;
  }

}

这个算法的棘手部分是检查一个元素是否是一个数组。还有一个问题是Java中的数组应该用它们的大小声明。

3 个答案:

答案 0 :(得分:2)

无论嵌套多深,您都可以编写一种方法,将多种Object压缩成List<Integer>。以下方法适用于int[]int[][]IntegerInteger[]Integer[][]List<Integer>List<List<Integer>>,{{ 1}}等(您可以轻松地让它返回List<int[]>)。

int[]

然而,这种事情是非常可怕的想法。如果您发现自己编写了大量public static List<Integer> flatten(Object object) { List<Integer> list = new ArrayList<>(); helper(object, list); return list; } private static void helper(Object object, List<Integer> list) { if (object instanceof Integer) { list.add((Integer) object); } else if (object instanceof int[]) { for (int a : (int[]) object) list.add(a); } else if (object instanceof Object[]) { for (Object obj : (Object[]) object) helper(obj, list); } else if (object instanceof Iterable) { for (Object obj : (Iterable) object) helper(obj, list); } else { throw new IllegalArgumentException(); } } 支票,然后根据结果做了不同的事情,那么您很可能做出了一些糟糕的设计决策。

答案 1 :(得分:1)

您可能会发现实现Iterator flatten(Object ... items)更容易 - 返回正确大小的数组将涉及将所有条目移动两次(一次计数一次,一次填充)。 Iterator可以使用stack并展平所有Iterable但是它们是嵌套的。这样,所有数组和所有Collection s也会自然地变平。此外,阵列是如此2014年!!

这似乎有效。它利用apache collections.IteratorUtils在原始数组上创建迭代器。

private static class FlatteningIterator implements Iterator {

    // All fall to null at end.
    Object o;
    // It is an iterator.
    Deque<Iterator> stack = new LinkedList();
    // The next object to deliver.
    Object next;

    private FlatteningIterator(Object o) {
        this.o = o;
    }

    @Override
    public boolean hasNext() {
        // Keep looking until found one or exhausted
        while (next == null && (!stack.isEmpty() || o != null)) {
            if (o != null) {
                // Check o first.
                if (o instanceof Iterator) {
                    // Any kind of iterator?
                    stack.push((Iterator) o);
                } else if (o instanceof Iterable) {
                    // Any Iterable.
                    stack.push(((Iterable) o).iterator());
                } else if (o.getClass().isArray()) {
                    // Primitive array! Use apache IteratorUtils
                    stack.push(IteratorUtils.arrayIterator(o));
                } else {
                    // Just return the object.
                    next = o;
                }
                o = null;
            }

            // Still not found one?
            if (next == null) {
                // Get it from the current iterator?
                Iterator it = stack.peek();
                if (it != null) {
                    if (it.hasNext()) {
                        // Walk it.
                        o = it.next();
                    } else {
                        // Exhausted the iterator.
                        stack.remove();
                    }
                }

            }
        }
        return next != null;
    }

    @Override
    public Object next() {
        Object n = hasNext() ? next : null;
        next = null;
        return n;
    }

}

public static Iterator<Object> flatten(Object o) {
    return new FlatteningIterator(o);
}

public void test() {
    List<Object> test = new ArrayList<>();
    test.add("Hello");
    test.add(Arrays.asList(1, 2, new int[]{3, 6, 9, 12}, 4, 5));
    test.add("Bye");
    Iterator f = flatten(test);
    for (Object o : Iterables.in(f)) {
        System.out.print(o);
        if (f.hasNext()) {
            System.out.print(",");
        }
    }
    System.out.println();
}

答案 2 :(得分:0)

与ruby不同,java是一种静态类型语言。这意味着你不能真正拥有数组,包含int和数组作为元素(嗯,你可以 ......但你不应该)。

因此,在java中展平会看起来像这样(我用列表来做,因为为了示例它有点容易,但它是相同的想法):

public static List<String>  flatten(List<List<String>> list) {
   List<String> result = new LinkedList<~>();
   for(List<String> l: list) result.addAll(l);
   return result;
}