返回介绍

数学基础

统计学习

深度学习

工具

Scala

二、迭代器

发布于 2023-07-17 23:38:22 字数 12642 浏览 0 评论 0 收藏 0

  1. 迭代器并不是集合,而是逐个访问集合元素的一种方式。迭代器 it 的两个基本操作是 nexthasNext

    • it.next 方法会返回迭代器的下一个元素,并将迭代器的状态往前推进一步。如果没有更多元素可以返回,则 it.next 会抛出 NoSuchElementException 异常。
    • it.hasNext 方法可以获知是否还有更多的元素可以返回。
  2. ”遍历“迭代器所有元素的最直接方式是通过 while 循环:

    
    
    xxxxxxxxxx
    while(it.hasNext) println(it.next())
  3. scala 中的迭代器提供了 Traversable, Iterable, Seq 等特质中的大部分方法。如 it.foreach 方法可以用来对迭代器返回的每个元素执行给定的操作。采用 foreach 之后, while 循环等价于:

    
    
    xxxxxxxxxx
    it.foreach(println)
    • 也可以用 for 表达式来替代涉及到 foreach, map, filter, flatMap 的表达式。因此上述方式等价于:

      
      
      xxxxxxxxxx
      for (elem <- it) println(elem)
    • 迭代器的 foreach 方法和 Traversableforeach 方法的一个重要区别:

      • 对迭代器调用 foreach 之后,它执行完之后会将迭代器留在末尾。因此,对相同的迭代器再次调用 next 会抛出 NoSuchElementException 异常。
      • Traversable 调用 foreach 之后,会保持集合中的元素数量不变。再次调用 foreach 可以得到上一轮foreach 相同的结果。

      除了 foreach 操作之外,其它的操作比如 map,filter 等等也类似:在执行之后会将迭代器留在末尾。

      如:

      
      
      xxxxxxxxxx
      val it = Iterator("a", "bc", "def") val it2 = it.map(_.length) // 返回一个新的 Iterator[Int] 对象 it.next() // 抛出 NoSuchElementException 异常
    • 另一个例子是 dropWhile 方法,但是注意:itdropWhile 调用中被修改了。

      
      
      xxxxxxxxxx
      val it = Iterator("a", "bc", "def") val it2 = it.dropWhile(_.length <= 2) // 返回一个新的 Iterator[String] 对象 it.next() // 返回 "def"

      经过 dropWhile 调用之后, it 指向的是序列中的第三个单词 "def" 。注意,此时 itit2 都返回相同的序列元素。

    • 只有一个标准操作 duplicate 允许重用同一个迭代器:

      
      
      xxxxxxxxxx
      val (it1, it2) = it.duplicate

      duplicate 的调用会返回两个迭代器,其中每个迭代器都返回和 it 完全相同的元素。而且这两个迭代器相互独立:推进其中一个并不会影响另外一个。

      而原始的 it 迭代器在 duplicate 调用之后就被推进到末端,不再可用。

  4. 总体而言,如果你在调用迭代器的方法之后再也不访问它,则迭代器的行为跟集合很像。Scala 集合类库将这个性质显式表示为一个名为 TraversableOnce 的抽象,这是TraversableIterator 的公共超类特质。

    正如其名称所示,TraversableOnce 对象可以用 foreach 来遍历,但是在遍历之后该对象的状态并无规定。

    • 如果 TraversableOnce 对象实际上是一个 Iterator,则遍历之后它将位于末端。
    • 如果 TraversableOnce 对象实际上是一个Traversable,则遍历之后它将保持原样。

    TraversableOnce 的一个常见用法是作为既可以接收迭代器、又可以接收可遍历集合的方法的入参类型声明。比如,Traversable 特质的 ++ 方法,它接收一个 TraversableOnce 参数,从而可以追加来自迭代器或可遍历集合的元素。

  5. 有时候希望有一个可以“向前看” 的迭代器,这样就可以检查下一个要返回的元素,但是并不向前推进。

    考虑这样的场景:从一个返回字符串的迭代器中迭代,并且跳过开头的空字符串。一种做法是:

    
    
    xxxxxxxxxx
    def func(it: Iterator[String])={ while (! it.netx().isEmpty){ println(it.next()) } }

    问题在于:

    • 如果 it.next() 返回的是空字符串,则该循环会跳过空字符串并且it 指向下一个字符串。
    • 如果 it.next() 返回的是非空字符串,那么循环结束并且it 指向下一个字符串,在这个过程中这个非空字符串完全得不到处理。

    这个问题的解决方案是采用带缓冲的迭代器,即 BufferedIterator 特质的实例。BufferedIteratorIterator 的子特质,它提供了一个额外的方法 head 。对一个带缓冲的迭代器调用 head 方法会返回它的当前元素,但是并不会推进到下一个元素。

    
    
    xxxxxxxxxx
    def func(it: BufferedIterator[String])={ while (! it.head.isEmpty){ println(it.next()) } }
  6. 每个迭代器都可以被转换为带缓冲的迭代器,方法是调用迭代器的 buffered 方法。

    
    
    xxxxxxxxxx
    val it = Iterator(1,2,3,4) val bit = it.buffered println(bit.head) // 打印 1 。只是查看,并不推进 println(bit.next()) // 打印 1 。向前推进 println(bit.next()) // 打印 2 。向前推进
  7. Iterator 特质包含的操作:

    • 抽象方法:

      • it.next():返回迭代器中的下一个元素,并将 it 推进到下一步。
      • it.hasNext :如果 it 能返回下一个元素,则返回 true
    • 创建另一种迭代器:

      • it.buffered:返回一个包含 it 所有元素的带缓冲的迭代器。
      • it grouped size:返回一个以固定大小的“分段” 来交出 it 元素的迭代器。
      • it sliding size:以固定大小的滑动窗口交出 it 元素的迭代器。
    • 拷贝:

      • it copyToBuffer buf:将 it 返回的所有元素拷贝到缓冲 buf
      • it copyToArray(arr,s,k):将 it 返回的最多 k 个元素拷贝到数组 arr,从数组的下标 s 开始。后两个入参皆为可选。
    • 复制:

      • it.duplicate:返回一对新的迭代器,它们都相互独立地返回 it 所有的元素。
    • 添加:

      • it1 ++ it2:返回 it1 所有元素,以及 it2 所有元素的迭代器。
      • it padTo (len, x):返回一个迭代器,新的迭代器返回 it 所有元素,以及 x 的拷贝直到返回元素的总长度达到 len
    • 映射:

      • it map f:通过对 it 返回的每个元素应用函数 f 得到的迭代器。
      • it flatMap f:通过对 it 返回的每个元素应用函数 f ,其中 f 返回的结果是迭代器,将 f 返回迭代器结果通过 ++ 拼接得到的迭代器。
      • it collect f:通过对 it 返回的每个元素应用函数 f,并将有定义的结果收集起来得到的迭代器。注意这里的 f 必须是一个偏函数 PartialFunction
    • 转换:

      • it.toArray/toList/toIterable/toSeq/toIndexSeq/toStream/toSet/toMap:将 it 返回的元素收集到数组/列表/Iterable/Seq/IndexSeq/Stream/Set/Map
    • 大小信息:注意:大小信息指的是从 it 当前位置开始的大小,而不从头开始。

      • it.isEmpty:测试迭代器是否为空(跟 hasNext 相反)。
      • it.noEmpty:测试迭代器是否非空(跟 hasNext 相同)。
      • it.size:返回 it 元素数量。注意:该操作之后,it 将位于末端。
      • it.length:等价于 it.size 。注意:该操作之后,it 将位于末端。
      • it.hasDefinitSize:如果已知将返回有限多的元素,则返回 true 。(默认同 isEmpty)。
    • 元素获取:

      • it find p:以Option返回 it 中首个满足条件 p 的元素。如果没有满足条件的,则返回 None

        注意:迭代器会推进到刚好跳过首个满足p 的元素,如果没找到则推进到末端。

      • it indexOf x:返回 it 中首个等于 x 元素的下标。注意:迭代器会推进到刚好跳过首个 x 的位置。如果找不到,则返回 -1,并且it 推进到末端。

      • it indexWhere p:返回 it 中首个满足条件p 的元素的下标。注意:迭代器会推进到刚好跳过首个满足p 的元素。如果找不到,则返回 -1,并且it 推进到末端。

    • 子迭代器:

      • it take n:返回 it 的头 n 个元素的迭代器。注意:it 将推进到第 n 个元素最后的位置,如果少于 n 个元素则 it 将推进到末端。
      • it drop n:返回从 it 的第 n+1 个元素开始的迭代器。注意:it 将推进到与新迭代器相同的位置。
      • it slice (m, n):返回从 it 的第 m 个元素开始到第 n 个元素之前为止(不包含)的元素的迭代器。
      • it takeWhile p : 返回it 中连续位置、直到满足条件 p 的元素的迭代器。
      • it dropWhile p :返回跳过 it 中连续位置、直到满足条件 p 的元素的迭代器。
      • it filter p:返回 it 中所有满足条件 p 的元素的迭代器。
      • it withFilter p:同 it filter p。这是为了支持 for 表达式语法。
      • it filterNot p:返回 it 中所有不满足条件 p 的元素的迭代器。
    • 划分:

      • it partition p:将 it 划分为两个迭代器,其中一个返回 it 中所有满足条件 p 的元素;另一个返回 it 中所有不满足条件 p 的元素。
    • 元素条件判断:

      • it forall p:返回是否 it 中所有元素满足条件p 的布尔值。
      • it exists p:返回是否 it 中存在元素满足条件p 的布尔值。
      • it count p:返回 it 中满足条件 p 的元素数量。
    • 折叠:

      • (z /: it)(op):以z 开始从左向右依次对 it 中的连续元素应用二元操作 op
      • (it :\ z)(op):以 z 开始从右向左依次对 it 中的连续元素应用二元操作 op
      • it.foldLeft(z)(op):同 (z /: it)(op)
      • it.foldRight(z)(op):同 (it :\z)(op)
      • it reduceLeft op:从左向右依次对非空迭代器 it 的连续元素应用二元操作 op
      • it reduceRight op:从右向左依次对非空迭代器 it 的连续元素应用二元操作 op
    • 特殊折叠:

      • it.sum:迭代器 it 中所有元素值的和。
      • it.product:迭代器 it 中所有元素值的乘积。
      • it.min:迭代器 it 中所有元素值的最小值。
      • it.max:迭代器 it 中所有元素值的最大值。
    • zip

      • it1 zip it2:返回由 it1it2 对应元素的对偶组成的新迭代器。
      • it1 zipAll (it2, x, y):返回由 it1it2 对应元素的对偶组成的新迭代器,其中较短的序列用 xy 的元素延展成相同的长度。
      • it zipWithIndex:返回由it 中的元素及其下标的对偶组成的新迭代器。
    • 更新:

      • it1 patch (i, it2, r):将 it1 中从位置 i 开始的 r 个元素替换成 it2 的元素得到的新迭代器。
    • 比较:

      • it1 sameElement it2:测试是否 it1it2 包含相同顺序的相同元素。
    • 字符串:

      • it addString (b, start, sep, end):将一个显示了 it 所有元素的字符串添加到 StringBuilder b 中,元素以 sep 分隔并仅考虑 startend 之间的元素。
      • it mkString ( start, seq, end):将迭代器转换为一个显示了 it 所有元素的字符串, 元素以 sep 分隔,并仅考虑 startend 之间的元素。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文