Scala Lazy Collection可以解释一下以下行为

时间:2015-11-15 13:33:09

标签: scala

我有一个普通的列表,并在其上定义了两个过滤器。我使用第一个过滤器过滤列表,然后使用下一个过滤器过滤输出并获取最后一个元素。

  1. 我在List对象lst(NORMAL LIST)
  2. 上进行上述操作
  3. 我正在lst.view(LAZY LIST)上进行上述操作
  4. 第二个操作似乎需要更多迭代。似乎在某一点上重新开始操作。请找到下面的代码。有人可以解释原因吗?

    object SolutionTest {
      val lst = List(("Mark", 32), ("Bob", 22), ("Jane", 8), ("Jill", 21),("Nick", 50), ("Nancy", 42), ("Mike", 19), ("Sara", 12), ("Paula", 42),("John", 21))
                                                  //> lst  : List[(String, Int)] = List((Mark,32), (Bob,22), (Jane,8), (Jill,21), 
                                                  //| (Nick,50), (Nancy,42), (Mike,19), (Sara,12), (Paula,42), (John,21))
        lst.size                                  //> res0: Int = 10
    
      def filter1(tup:(String, Int)):Boolean={
        println("from filter1 "+ tup)
        val (_, age) = tup
        age > 17
      }                                               //> filter1: (tup: (String, Int))Boolean
    
      def filter2(tup:(String, Int)):Boolean={
        println("from filter2 "+ tup)
        val (name, _) = tup
        name.startsWith("J")
      }                                               //> filter2: (tup: (String, Int))Boolean
    
    
    //NORMAL LIST                                                  
    lst.filter(filter1).filter(filter2).last  //> from filter1 (Mark,32)
                                                  //| from filter1 (Bob,22)
                                                  //| from filter1 (Jane,8)
                                                  //| from filter1 (Jill,21)
                                                  //| from filter1 (Nick,50)
                                                  //| from filter1 (Nancy,42)
                                                  //| from filter1 (Mike,19)
                                                  //| from filter1 (Sara,12)
                                                  //| from filter1 (Paula,42)
                                                  //| from filter1 (John,21)
                                                  //| from filter2 (Mark,32)
                                                  //| from filter2 (Bob,22)
                                                  //| from filter2 (Jill,21)
                                                  //| from filter2 (Nick,50)
                                                  //| from filter2 (Nancy,42)
                                                  //| from filter2 (Mike,19)
                                                  //| from filter2 (Paula,42)
                                                  //| from filter2 (John,21)
                                                  //| res1: (String, Int) = (John,21)
    
    //LAZY LIST
    lst.view.filter(filter1).filter(filter2).last
                                                  //> from filter1 (Mark,32)
                                                  //| from filter2 (Mark,32)
                                                  //| from filter1 (Bob,22)
                                                  //| from filter2 (Bob,22)
                                                  //| from filter1 (Jane,8)
                                                  //| from filter1 (Jill,21)
                                                  //| from filter2 (Jill,21)
                                                  //| from filter1 (Mark,32) RESTARTING THE OPERATION HERE!!!
                                                  //| from filter2 (Mark,32)
                                                  //| from filter1 (Bob,22)
                                                  //| from filter2 (Bob,22)
                                                  //| from filter1 (Jane,8)
                                                  //| from filter1 (Jill,21)
                                                  //| from filter2 (Jill,21)
                                                  //| from filter1 (Nick,50)
                                                  //| from filter2 (Nick,50)
                                                  //| from filter1 (Nancy,42)
                                                  //| from filter2 (Nancy,42)
                                                  //| from filter1 (Mike,19)
                                                  //| from filter2 (Mike,19)
                                                  //| from filter1 (Sara,12)
                                                  //| from filter1 (Paula,42)
                                                  //| from filter2 (Paula,42)
                                                  //| from filter1 (John,21)
                                                  //| from filter2 (John,21)
                                                  //| res2: (String, Int) = (John,21)
    }
    

1 个答案:

答案 0 :(得分:6)

评论前的第一个操作"在此重新开始"来自寻找过滤序列中的第一个元素。 Scala开始过滤,直到找到结果(Jill,21)中的第一个元素。在此之后,它实际上开始处理整个序列。

这是因为类last中的TraversableLike implemented是这样的:

def last: A = {
  var lst = head
  for (x <- this)
    lst = x
  lst
}

在真正完成序列之前调用head。简单view不使用缓存,因此在过滤一点以查找head后,必须重新启动。

视图上的其他功能可能无法显示此重新启动行为。例如,lst.view.filter(filter1).filter(filter2).lastOption只运行一次序列。