【问题标题】:Iterators over same collection in for-loopfor循环中相同集合的迭代器
【发布时间】:2014-01-11 09:11:58
【问题描述】:

假设我想生成集合子集的所有组合。由于subset 返回iterator,我不想将其转换为严格的。

def gen(A: Set[Int]) = {
  val it0 = A.subsets
  val it1 = A.subsets
  for(a <- it0; b <- it1) yield (a,b)
}

但这不是我想要的。例如gen(Set(1,2,3)).foreach(println) 返回:

(Set(),Set())
(Set(),Set(1))
(Set(),Set(2))
(Set(),Set(3))
(Set(),Set(1, 2))
(Set(),Set(1, 3))
(Set(),Set(2, 3))
(Set(),Set(1, 2, 3))

似乎只有第二个迭代器迭代所有子集。为什么会有这样的行为,有没有一种很好的方法可以避免这种情况?

【问题讨论】:

    标签: scala iterator


    【解决方案1】:

    请注意,it0it1Iterators。你不能像这样使用迭代器:

    val it0 = Iterator(1, 2)
    val it1 = Iterator(1, 2)
    
    (for { a <- it0; b <- it1 } yield (a, b)).toList
    // List[(Int, Int)] = List((1,1), (1,2))
    

    这里的原因是你不能重复IteratorIterator 是可变的。对于it0 的第一个元素,您已经迭代了it1,所以it1 对于it0 的下一个元素是空的。

    您应该为第一个迭代器的每个元素重新创建第二个迭代器:

    def gen(A: Set[Int]) = 
      for{
        a <- A.subsets
        b <- A.subsets
      } yield (a,b)
    

    或将Iterator 转换为不可变集合:

    def gen(A: Set[Int]) = {
      val it = A.subsets.toSeq
      for(a <- it; b <- it) yield (a,b)
    }
    

    【讨论】:

    • 啊,是的,谢谢。我的想法有缺陷。我想避免将其转换为不可变集合。
    • 但是现在我测试了它,我的算法(它也做一些其他的事情)比我使用不可变集合的初始解决方案慢 3 倍。太糟糕了。只是想节省一些空间。
    • @Kigyo:implementation of subsets 很昂贵,包括对昂贵的toIndexedSeq 操作的N 调用(1 代表len,从0Set#size)。
    猜你喜欢
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 2016-06-20
    • 1970-01-01
    • 2020-06-19
    相关资源
    最近更新 更多