【问题标题】:Interview: Design an iterator for a collection of collections采访:为集合设计一个迭代器
【发布时间】:2011-03-20 14:48:21
【问题描述】:

为java中的集合设计一个迭代器。迭代器应该隐藏嵌套,允许您迭代属于所有集合的所有元素,就好像您正在使用单个集合一样

【问题讨论】:

  • 设计有什么用?原型?实施?
  • 两者,接口是什么,你将如何实现它?
  • 如果这是你的工作面试,你为什么要在这里发布而不是呢?
  • 我不会自己设计任何东西——我只会使用 Google Collections:guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/…。话虽如此,如果您真的想自己做的话,实现非常简单。
  • @user399950 你的要求是这样的——Collection parent = new ArrayList();集合 slave1 = new ArrayList(); slave1.add(10); slave1.add(20);设置 slave2 = new HashSet(); slave2.add(30); slave2.add(40);父.add(slave1); parent.add(slave2);

标签: java collections iterator


【解决方案1】:

这是一个老问题,但现在(2019 年)我们有 JDK8+ 的好东西。特别是,我们有流,这使这项任务变得简单:

public static <T> Iterator<T> flatIterator(Collection<Collection<T>> collections) {

    return collections.stream()
            .filter(Objects::nonNull)
            .flatMap(Collection::stream)
            .iterator();
}

我正在过滤 null 内部集合,以防万一......


编辑:如果您还想从内部集合中过滤掉 null 元素,只需在 flatMap 之后添加一个额外的非空过滤器:

return collections.stream()
        .filter(Objects::nonNull)
        .flatMap(Collection::stream)
        .filter(Objects::nonNull)
        .iterator();

【讨论】:

    【解决方案2】:

    这是一个可能的实现。请注意,我没有实现 remove():

    public class MultiIterator <T> implements Iterator<T>{
    
        private Iterator<? extends Collection<T>> it;
        private Iterator<T> innerIt;
        private T next;
        private boolean hasNext = true;
    
        public MultiIterator(Collection<? extends Collection<T>> collections) {
            it = collections.iterator();    
            prepareNext();
        }
    
        private void prepareNext() {
            do {
                if (innerIt == null || !innerIt.hasNext()) {
                    if (!it.hasNext()) {
                        hasNext = false;
                        return;
                    } else
                        innerIt = it.next().iterator();
                }
            } while (!innerIt.hasNext());
    
            next = innerIt.next();
        }
    
        @Override
        public boolean hasNext() {
            return hasNext;
        }
    
        @Override
        public T next() {
            if (!hasNext)
                throw new NoSuchElementException();
            T res = next;
            prepareNext();
            return res;
        }
    
        @Override
        public void remove() {
            //TODO
        }
    
    }
    

    【讨论】:

    • 您的解决方案不考虑给定集合中的空值。修复:在 prepareNext() 中,内部循环应该一直持续到 it.next() 不为空,然后再执行 it.next().iterator(),如果没有非空集合对象留给它,它应该退出我们使用。
    【解决方案3】:

    this post 中,您可以看到两个实现,唯一(次要)区别是它采用迭代器的迭代器而不是集合的集合。

    这种差异与以循环方式迭代元素的要求相结合(OP 在 this 问题中未要求的要求)增加了将迭代器复制到列表。

    第一种方法是惰性的:它只会在请求该元素时迭代一个元素,我们必须付出的“代价”是代码更复杂,因为它需要处理更多的边缘情况:

    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.NoSuchElementException;    
    
    public class MultiIterator<E> implements Iterator {
    
        List<Iterator<E>> iterators = new LinkedList<>();
        Iterator<E> current = null;
    
        public MultiIterator(Iterator<Iterator<E>> iterator) {
            // copy the iterators into a list
            while (iterator.hasNext()) {
                iterators.add(iterator.next());
            }
        }
    
        @Override
        public boolean hasNext() {
            boolean result = false;
            if (iterators.isEmpty() && (current == null || !current.hasNext())) {
                return false;
            }
    
            if (current == null) {
                current = iterators.remove(0);
            }
    
            while (!current.hasNext() && !iterators.isEmpty()) {
                current = iterators.remove(0);
            }
    
            if (current.hasNext()) {
                result = true;
            }
            return result;
        }
    
        @Override
        public E next() {
            if (current == null) {
                try {
                    current = iterators.remove(0);
                } catch (IndexOutOfBoundsException e) {
                    throw new NoSuchElementException();
                }
            }
            E result = current.next(); // if this method was called without checking 'hasNext' this line might raise NoSuchElementException which is fine
            iterators.add(current);
            current = iterators.remove(0);
            return result;
        }
    
        // test
        public static void main(String[] args) {
            List<Integer> a = new LinkedList<>();
            a.add(1);
            a.add(7);
            a.add(13);
            a.add(17);
            List<Integer> b = new LinkedList<>();
            b.add(2);
            b.add(8);
            b.add(14);
            b.add(18);
            List<Integer> c = new LinkedList<>();
            c.add(3);
            c.add(9);
            List<Integer> d = new LinkedList<>();
            d.add(4);
            d.add(10);
            d.add(15);
            List<Integer> e = new LinkedList<>();
            e.add(5);
            e.add(11);
            List<Integer> f = new LinkedList<>();
            f.add(6);
            f.add(12);
            f.add(16);
            f.add(19);
            List<Iterator<Integer>> iterators = new LinkedList<>();
            iterators.add(a.iterator());
            iterators.add(b.iterator());
            iterators.add(c.iterator());
            iterators.add(d.iterator());
            iterators.add(e.iterator());
            iterators.add(f.iterator());
            MultiIterator<Integer> it = new MultiIterator<>(iterators.iterator());
            while (it.hasNext()) {
                System.out.print(it.next() + ","); // prints: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
            }
        }
    }
    

    第二个(“贪婪”地将所有迭代器中的所有元素按请求的顺序复制到列表中,并将迭代器返回到该列表):

    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    
    public class MultiIterator<E> {
    
        Iterator<Iterator<E>> iterator = null;
        List<E> elements = new LinkedList<>();
    
        private MultiIterator(Iterator<Iterator<E>> iterator) {
            this.iterator = iterator;
        }
    
        private void copyElementsInOrder() {
            List<Iterator<E>> iterators = new LinkedList<>();
            // copy the iterators into a list
            while (iterator.hasNext()) {
                iterators.add(iterator.next());
            }
            // go over the list, round-robin, and grab one
            // element from each sub-iterator and add it to *elements*
            // empty sub-iterators will get dropped off the list
            while (!iterators.isEmpty()) {
                Iterator<E> subIterator = iterators.remove(0);
                if (subIterator.hasNext()) {
                    elements.add(subIterator.next());
                    iterators.add(subIterator);
                }
            }
        }
    
        public static <E> Iterator<E> iterator(Iterator<Iterator<E>> iterator) {
            MultiIterator<E> instance = new MultiIterator<>(iterator);
            instance.copyElementsInOrder();
            return instance.elements.iterator();
        }
    
        // test
        public static void main(String[] args) {
            List<Integer> a = new LinkedList<>();
            a.add(1);
            a.add(7);
            a.add(13);
            a.add(17);
            List<Integer> b = new LinkedList<>();
            b.add(2);
            b.add(8);
            b.add(14);
            b.add(18);
            List<Integer> c = new LinkedList<>();
            c.add(3);
            c.add(9);
            List<Integer> d = new LinkedList<>();
            d.add(4);
            d.add(10);
            d.add(15);
            List<Integer> e = new LinkedList<>();
            e.add(5);
            e.add(11);
            List<Integer> f = new LinkedList<>();
            f.add(6);
            f.add(12);
            f.add(16);
            f.add(19);
            List<Iterator<Integer>> iterators = new LinkedList<>();
            iterators.add(a.iterator());
            iterators.add(b.iterator());
            iterators.add(c.iterator());
            iterators.add(d.iterator());
            iterators.add(e.iterator());
            iterators.add(f.iterator());
            Iterator<Integer> it = MultiIterator.<Integer>iterator(iterators.iterator());
            while (it.hasNext()) {
                System.out.print(it.next() + ","); // prints: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
            }
        }
    }
    

    我包含了一个简单的“测试”代码,以展示使用 MultiIterator 的方法,这并不总是微不足道的(因为使用了泛型),正如您在网上看到的那样:

    Iterator<Integer> it = MultiIterator.<Integer>iterator(iterators.iterator());
    

    【讨论】:

      【解决方案4】:

      这是另一个实现:

      import java.util.Iterator;
      import java.util.NoSuchElementException;
      
      import static java.util.Collections.emptyIterator;
      
      public class Multiterator<E> implements Iterator<E> {
          private Iterator<Iterator<E>> root;
          private Iterator<E> current;
      
          public Multiterator(Iterator<Iterator<E>> root) {
              this.root = root;
              current = null;
          }
      
          @Override
          public boolean hasNext() {
              if (current == null || !current.hasNext()) {
                  current = getNextNonNullOrEmpty(root);
              }
              return current.hasNext();
          }
      
          private Iterator<E> getNextNonNullOrEmpty(Iterator<Iterator<E>> root) {
              while (root.hasNext()) {
                  Iterator<E> next = root.next();
                  if (next != null && next.hasNext()) {
                      return next;
                  }
              }
              return emptyIterator();
          }
      
          @Override
          public E next() {
              if (current == null) {
                  throw new NoSuchElementException();
              }
              return current.next();
          }
      }
      

      【讨论】:

        【解决方案5】:

        首先看一下java.util.LinkedList中迭代器的实现

        http://www.docjar.com/html/api/java/util/LinkedList.java.html

        从那里您的任务很容易,只需实现一个迭代器,该迭代器考虑到它正在迭代集合这一事实。

        问候。

        【讨论】:

        • 它有负值:它声称分析 LinkedList 以某种方式给你一个答案,但它没有(真正的挑战是两层实现,而不是从集合中获取迭代器)。
        【解决方案6】:

        如果你只需要使用 java 迭代器:它只有 hasNext()、next() 和 remove(),我想你必须绕过它。

        像处理二维数组一样处理它,即使用外循环和内循环,因为它们具有相同的“排列”但数据类型不同。在处理过程中,您会将它们转移到新的集合中。

        所以也许是一个私有方法:

            private void convertToSingleCollection()
            {
        
        
                 while("column")
                 {
                    //convert the "column" to an arra
        
        
                   for( "Row")
                   {
                    //add to newCollection here
                   }
        
                  //remove the processed column from CollectionOFcollection
                 } 
            }
            //call the above method in your constructor
        
        
            public iterator<T> Iterator()
            {
               newCollection.iterator();
            }
        
            public boolean hasNext()
            {
               return Iterator().hasNext()
            }
        
            public T next()
            {
               if(!hasNext())
               {
                //exception message or message
               }
               else
                   //return "next"
            }
        

        结束

        我希望这会有所帮助。我想应该有其他方法可以解决它。

        【讨论】:

          猜你喜欢
          • 2014-05-17
          • 1970-01-01
          • 2015-05-17
          • 2018-01-08
          • 2018-04-08
          • 2012-07-03
          • 2014-04-24
          • 1970-01-01
          相关资源
          最近更新 更多