我正在阅读一本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中的数组应该用它们的大小声明。
答案 0 :(得分:2)
无论嵌套多深,您都可以编写一种方法,将多种Object
压缩成List<Integer>
。以下方法适用于int[]
,int[][]
,Integer
,Integer[]
,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;
}