美文网首页
11迭代和包含

11迭代和包含

作者: jarod_chan | 来源:发表于2016-05-02 13:49 被阅读43次

for语法体系用来处理序列上的迭代。列表,向量,字符串,比特字符串,输入端口,哈希表都能被当做序列使用。构造函数比如in-range也能缠身序列。
for变种以各种方式积累迭代结果,但是它们的语法形式相同。

  (for ([id sequence-expr] ...)
    body ...+)

for循环迭代通过sequence-expr产生的序列。序列的每一个元素,都会绑定到id,然后执行body代码。

  >(for ([i '(1 2 3)])
    (display i))
  123
  >(for ([i "abc"])
      (printf "~a..." i))
  a...b...c...
  >(for ([i 4])
      (display i))
  0123

for/list是一种更加racket风格的变种。它会累积方法体的结果到一个列表,而不是单纯执行方法体。更加专业的术语,for/list实现了一种列表包含。
>(for/list ([i '(1 2 3)]
(* i i))
'(1 4 9)
>(for/list ([i "abc"])
i)
'(#\a #\b #\c)
>(for/list ([i 4])
i)
'(0 1 2 3)
for语法的完全形式可以同时平行的迭代多个序列,for*内嵌迭代而不是平行的执行。for系列的语法辩题,都能使用条件来过滤迭代项。

11.1 序列构造器

in-range函数产生了一个数字的序列,可以设置一个可选的开始值,一个结束值(结束前的最后一个),一个可选的步进值。使用一个非负整数k直接产生一个序列的代码(in-range k)

>(for ([i 3])
    (display i))
012
>(for ([i (in-range 3)])
    (display i))
012
>(for ([i (in-range 1 4])
    (display i))
123
>(for ([i (in-range 1 4 2)])
    (display i))
13
>(for ([i (in-range 1 4 1/2])
     (printf "~a" i))
1 3/2 5/2 3 7/2

in-naturals类似,处理开始数字必须是一个非负整数(默认是0),步进值总是1,但是没有上限。它不会终止除非异常或者其它的跳出。

>(for ([i (in-naturals)])
    (if (= i 10)
        (error "too much")
        (display i)))

stop-before,stop-after函数通过一个序列和一个谓词判断产生一个新的序列。产生的新序列和原来的序列一样,但是在谓词判断返回true以前或者以后马上停止。

>(for ([i (stop-before "abc def"
               char-whitespace?)])
         (display i))
abc

in-list,in-vector,in-string明确了产生序列的类型。如果赋值了一个错误类型,会抛出一个异常。因为避免了运行时的类型分发,代码的效率更高。

11.2for和for*

更加复杂的for语句

>(for (clause ...)
    body ...+)
    clause= [id sequence-expr]
               | #:when boolean-expr
               | #:unless boolean-expr

当有多个[id sequence-expr]子句,它会平行遍历多个序列。当其中一个平行序列结束,整个遍历就会结束。利用这种特性,结合in-naturals这种产生无限序列的构造器,可以产生索引。

>(for ( [i (in-naturals 1)]
           [chapter '("Intro" "Details" "Conclusion")])
        (printf "Chapter ~a. ~a\n" i chapter))
Chapter 1. Intro
Chapter 2. Details
Chapter 3. Conclusion

for*和for类似,但是内嵌迭代而不是平行。
for之于for正如let之于let
#:when boolean-expr形式只有在返回true时,方法体才会执行。在一个for形式中,使用when会造成迭代内嵌,即使在for里面也是这样。
#:unless boolean-expr 与when相反。

11.3for/list 和 for*/list

for/list和for有一样的语法形式,执行方法体获得一个新列表。
使用#:when可以裁剪结果列表。
>(for/list ([i (in-naturals 1)]
[chapter '("Intro" "Details" "Conclusion")]
#:when (odd? i))
chapter)
'("Intro" "Conclusion")
#:when 的裁剪功能在for/list更加有用。原始的when表达式会产生一个#<void>值而不是忽略返回值。
'for/list'形式和for*类似,内嵌多个迭代。
>(for
/list ([book '("Guide" "Ref.")]
[chapter '("Intro" "Details")])
(string-append book " " chapter))
'("Guide Intro" "Guide Details" "Ref. Intro" "Ref. Details")
for*/list和for/list的内嵌形式并不相同。内嵌的for/list会产生一个列表的列表,而不是展开的列表。它更像#:when形式造成的内嵌。

11.4 fro/vector 和for*/vector

for/vector语法和for/list相似,只是构造向量而不是列表。它们都能指定#:length参数。

>(let ([chapters '("Intro" "Details" "Conclusion")])
       (for/vector #:length (length chapters) ([i (in-naturals 1)]
                                                               [chanpter chapters])
        (string-append (number->string i) ". " chapter)))
'#("1. Intro" "2. Details" "3. Conclusion")

如果length参数被提供,当向量填满或者迭代完成,迭代自动完成。如果length超过请求的迭代,剩下的使用make-vector使用初始化。

11.5for/and和for/or

for/and形式使用and合并迭代,如果结果是#f则停止。

>(for/and ([chapter '("Intro" "Details" "Conclusion")])
    (equal? chapter "Intro"))
#f

for/or形式使用or合并迭代,如果结果是#t则停止。

>(for/or ([chanpter '("Intro" "Details" "Conclusion")])
      (equal? chapter "Intro"))
#t

for*/andfor*/or提供相同的功能但是内嵌迭代。

11.6 for/first和for/last

for/first形式返回第一次方法体执行的结果,忽略其它迭代。#:when子句在这种形式里更有用。
>(for/list ([chanpter '("Intro" "Details" "Conclusion" "Index")]
#:when (not (equal? chapter "Intro")))
chanpter)
"Details"
如果方法体被执行了0次,结果是#f。
for/last运行迭代,返回最后一个迭代的值。如果没有迭代,则返回#f。

>(for/last ([chapter '("Intro" "Details" "Conclusion" "Index")
                  #:when (not (equal? chapter "Index"))])
    chapter)
"Conclusion"

for*/first和'for*/last'提供了类似的内嵌的功能

11.7for/fold和for*/fold

for/fold是一种很普遍的用来收集迭代结果的方式。它的语法和for只有稍微的不同,因为累加器变量必须在开始的时候定义。

(for/fold ([accum-id init-expr] ...)
             (clause ...)
  body ..+)

在简单的情况下只有一个[accum-id init-expr]被提供,函数的运行结果则是最后的accum-id值,它开始的初始值是init-expr。

>(for/fold ([len 0])
                ([chanpter '("Intro" "Conclusion")])
      (+ len (string-length chapter)))
15
>(fro/fold ([prev #f])
                ([i (in-naturals 1)]
                 [chapter '("Intro" "Details" "Details" "Conclusion")]
                  #:when (not (equal? chanpter prev)))
       (printf "~a. ~a\n" i chanpter)
       chapter)
1. Intro
2. Details
4. Conclusion
"Conclusion"

当多个累加器被指定,方法体最后必须产生多个值,与每个累加器对应。for/fold本身也会返回多个值。

>(for/fold ([prev #f]
                 [counter 1])
                ([chapter '("Intro" "Details" "Details" "Conclusion")]
                 #:when (not (equal? chapter prev)))
    (printf "~a. ~a\n" counter chapter)
    (values chapter 
               (add1 counter)))
1. Intro
2. Details
3. Conclusion
"Conclusion"
4

11.8多值序列

和函数和表达式产生多值一样,序列的迭代也能产生多个值。比如,哈希表就可以长生一个两个值的迭代。
和let-values可以绑定多个结果到多个标识符,for也可以绑定多值的序列元素到多个迭代标识

>(for ([k v] #hash(("apple" .1) ("banana" . 3))])
    (printf "~a count: ~a\n" k v))
apple count: 1
banana count: 3

多值绑定能在多个for变种里使用。

>(for*/list ([k v) #hash(("apple" . 1) ("banana" . 3))]
                 [(i) (in-range v)])
'("apple" "banana" "banana" "banana")

11.9跳出迭代

(for (clause ...)
  body-or-break ... body)
  clause=[id sequence-expr]
        |#:when boolean-expr
        |#:unless boolean-expr
        |break
  body-or-break=body
        |break
  break=#:break boolean-expr
        |#:final boolean-expr

#:break#:final能使用在绑定语句和方法体里。在绑定语句里,#:break作用和'#:unless'很像,但是如果boolean-expr是true,所有序列迭代都会停止。在方法体里,#:break和在语句里有着相同的效果,它会阻断当前迭代以后的方法体执行。

>(for ([book '("Cuide" "Story" "Reference")]
          #:unless (equal? book "Story")
          [chapter '("intor" "Details" "Conclusion")])
      (printf "~a ~a\n"  book chapter))
Guide Intro
Guide Details
Guide Conclusion
Reference Intro
Reference Details
Reference Conclusion

使用#:break则会终止整个迭代

>(for ([book '("Guide" "Story" "Reference")]
          #:break (equal? book "Story")
          [chapter '("Intro" "Details" "Conclusion")])
      (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
>(for* ([book '("Guide" "Story" "Reference")]
           [chapter '("Intro" "Details" "Conclusion")])
    #:break (and (equal? book "Story")
                        (equal? chanpter "Conclusion"))
    (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Story Intro
Story Details

#:final语句和#:break类似,但是不会马上终止迭代。它允许执行最后一次。

>(for*  ([book '("Guide" "Story" "Reference")]
            [chapter '("Intro" "Details" "Conclusion")])
      #:final (and (equal? book "Story")
                        (equal? chapter "Conclusion")
      (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Story Intro
Story Details
Story Conclusion
>(for ([book '("Guide" "Story" "Reference")]
          #:final (equal? book "Story")
          [chanpter '("Intro" "Details" "Conclusion")])
      (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Story Intro

11.10迭代效率

理想情况下,for迭代运行和你自己手动实现的递归调用一样快。但是手写的循环,一般指定了一种特定的数据,像列表。在这种情况下,手写循环直接使用car,cdr,而不是处理各种形式的序列然后分发他们到合适的迭代器。
for形式也可以达到手写循环的效率当提供足够多的迭代信息。特别的,子句应该有其中一个fast-clause形式。

fast-clause=[id fast-seq]
          |[(id) fast-seq]
          |[(id id) fast-indexed-seq]
          |[(id ...) fast-parallel-seq]

fast-seq=(in-range expr)
    |(in-range expr expr)
    |(in-range expr expr expr)
    |(in-naturals)
    |(in-naturals expr)
    |(in-list expr)
    |(in-vector expr)
    |(in-string expr)
    |(in-bytes expr)
    |(in-value expr)
    |(stop-before fast-seq predicate-expr)
    |(stop-after fast-seq predicate-expr)

fast-indexed-seq=(in-indexed fast-seq)
    |(stop-before fast-indexed-seq predicate-expr)
    |(stop-after fast-indexed-seq predicate-expr)

fast-parallel-seq=(in-parallel fast-seq ...)
    |(stop-before fast-parallel-seq predicate-expr)
    |(stop-after fast-parallel-seq predicate-expr)

相关文章

  • 11迭代和包含

    for语法体系用来处理序列上的迭代。列表,向量,字符串,比特字符串,输入端口,哈希表都能被当做序列使用。构造函数比...

  • stream系列——初识stream

    初识stream 1、对于迭代来说,包含内部迭代和外部迭代。 外部迭代:(程序逻辑自己控制迭代过程) 内部迭代:(...

  • Python 迭代器和生成器

    1. 迭代器 任何包含__iter__和__next__的函数将成为迭代器,而只包含__iter__的函数则是可迭...

  • python中可迭代对象、迭代器、生成器的关系

    可迭代对象与迭代器 1)可迭代对象包含迭代器。 2)如果一个对象拥有__iter__方法,其是可迭代对象;如果一个...

  • 【Python】语法学习6

    一、迭代 1.什么是迭代 注意:集合是指包含一组元素的数据结构。1.有序集合:list,tuple,str和Uni...

  • C++标准模板库

    STL包含了容器类(container)、迭代器(iterator)和算法(algorithm)三个部分 容器(C...

  • DL4J中文文档/模型/迭代器-1

    什么是迭代器? 数据集迭代器允许将数据轻松加载到神经网络中,并帮助组织批处理、转换和掩码。包含在Eclipse D...

  • Java8 新特征

    一、操作集合 二、循环迭代 三、函数式接口 只包含一个抽象方法,可以包含多个静态方法和默认方法,可以定义Java....

  • 23.Python迭代器

    迭代器是包含__next__的对象,当调用__next__方法时,迭代器返回其下一个值。迭代器并不等同于可迭代对象...

  • 如何用JAVA程序来查找链接列表是否包含循环

    查找链表是否包含循环的算法 迭代链表时使用快速和慢速两个指针。快速指针在每次迭代中移动两个节点,而慢速指针移动到一...

网友评论

      本文标题:11迭代和包含

      本文链接:https://www.haomeiwen.com/subject/cahkrttx.html