将多个Iterables包装到单个Iterable中

时间:2011-03-24 17:17:12

标签: java collections

说我有两个Collections

Collection< Integer > foo = new ArrayList< Integer >();
Collection< Integer > bar = new ArrayList< Integer >();

并说有时我想单独迭代它们,但有时一起。有没有办法在foobar周围创建一个包装器,以便我可以迭代组合对,但是只要foobar发生变化,它也会更新? (即Collection.addAll()不适合。)

例如:

Collection< Integer > wrapper = ... // holds references to both bar and foo

foo.add( 1 );
bar.add( 99 );

for( Integer fooInt : foo ) {
    System.out.println( fooInt );
} // output: 1

for( Integer barInt : bar ) {
    System.out.println( barInt );
} // output: 99

for( Integer wrapInt : wrapper ) {
    System.out.println( wrapInt );
} // output: 1, 99

foo.add( 543 );

for( Integer wrapInt : wrapper ) {
    System.out.println( wrapInt );
} // output: 1, 99, 543

谢谢!

5 个答案:

答案 0 :(得分:5)

使用GuavaIterables.concat方法。

Iterable<Integer> wrapped = Iterables.concat(foo, bar);

答案 1 :(得分:3)

我写了两个函数:

/**
 * Create an Iterator from multiple Iterators. The returned Iterator
 * traverses all elements from all sources, in the order, as if they belong
 * to the same source.
 * 
 * @param <T> type of elements
 * @param sources sources of the elements, in order of traversal
 * @return an iterator over multiple iterators in sequence
 */
public static <T> Iterator<T> concatenate(final Iterator<T> ... sources) {
    if (sources.length == 0) {
        return new Iterator<T>() {
            @Override public boolean hasNext() { return false; }
            @Override public T next() { throw new NoSuchElementException("end of iteration"); }
            @Override public void remove() { throw new IllegalStateException("no previous element"); }
        };
    }
    return new Iterator<T>() {

        Iterator<Iterator<T>> sourcesIterator = Arrays.asList(sources).iterator();
        Iterator<T> currentIterator = sourcesIterator.next();

        @Override
        public boolean hasNext() {
            if (currentIterator.hasNext()) {
                return true;
            } else {
                if (sourcesIterator.hasNext()) {
                    currentIterator = sourcesIterator.next();
                    return hasNext();
                } else {
                    return false;
                }
            }
        }

        @Override
        public T next() {
            if (hasNext()) {
                return currentIterator.next();
            } else {
                throw new NoSuchElementException("end of iteration");
            }
        }

        @Override
        public void remove() {
            currentIterator.remove();
        }
    };
}

/**
 * Create an Iterable from multiple Iterables. The returned Iterable
 * traverses all elements from all sources, in the order, as if they belong
 * to the same source.
 * 
 * @param <T> type of elements
 * @param sources sources of the elements, in order of traversal
 * @return an iterable over multiple iterators in sequence
 */
@SuppressWarnings("unchecked") // impossible to create a generic array
public static <T> Iterable<T> concatenate(final Iterable<T> ... sources) {
    return new Iterable<T>() {
        @Override
        public Iterator<T> iterator() {
            final Iterator[] iteratorsArrays = new Iterator[sources.length];
            for (int i = 0; i < sources.length; i++) {
                iteratorsArrays[i] = sources[i].iterator();
            }
            return concatenate(iteratorsArrays);
        }
    };
}

答案 2 :(得分:0)

查看Apache Commons Collections - CollectionUtils或IteratorUtils。有你想要的方法类型。

答案 3 :(得分:0)

一个简单的List列表并不是那么多样板:

List <List <Integer>> metalist = new ArrayList <List <Integer>> ();
metalist.add (foo);
metalist.add (bar);
for (List<Integer> list : metalist) 
    for (Integer wrapInt : list)
        System.out.println (wrapInt);

如果现在向foo foo.add (4);添加4,则只需重复2次循环。问题出在哪儿?

答案 4 :(得分:-1)

喜欢@barjak,但更短

public static <E> Collection<E> concat(Collection<E> ... es) {
    List<E> ret = new ArrayList<E>();
    for (Collection<E> e : es) ret.addAll(e);
    return ret;
}

public static <E> Iterable<E> viewOf(final Collection<E> ... es) {
    return new Iterable<E>() {
        public Iterator<E> iterator() {
            return concat(es).iterator();
        }
    };
}

Collection< Integer > foo = new ArrayList< Integer >();
Collection< Integer > bar = new ArrayList< Integer >();

// call as often as you like.
for(Integer i : concat(foo, bar))

// OR
Iterable<Integer> view = viewOf(foo, bar);

// call as often as you like.
for(Integer i : view)