12.3.1 用迭代器转换序列

到目前为止,我们只是用迭代器,从一段数据(如果有的话)生成序列。然而,迭代器通常用来以某种方式,进行序列的转换。作为一个简单的例子,这里有一个方法,把数字序列转换成平方序列:

IEnumerable<int>Squares(IEnumerable<int> numbers) {

foreach(int i in numbers)

yield return i * i;

}

我们使用的是熟悉的 foreach 结构,但是要记住,包含 yield return 语句的foreach,有了不同的含义,它不会提前进行循环,而是在需要时才计算。foreach 语句,为每次循环迭代生成元素的代码,对应于从输入序列中取出(pulling)一个元素,把零或多个元素推到(pushing)输出序列中(在前面的例子中,我们始终只生成一个元素)。如果想要实现 LINQ to Objects 中的泛型 Where 和 Select 方法,可以使用完全相同的方法。

有一个更复杂的例子,我们想实现 Zip 方法,与 F# 中的 Seq.zip 函数的功能相同;给它两个序列,将返回一个序列,包含的元素是把给定的序列连接成元组。在 .NET 4.0 的库中有这个方法,但我们要讨论一下,因为它能展示了一个有趣的问题;不能使用 foreach 同时从两个源序列取元素。从清单 12.8 中可以看到,唯一的选择是直接使用 IEnumerable<T> 和 IEnumerator<T> 接口。

清单 12.8 实现 Zip 方法 (C#)

public static IEnumerable<Tuple<T1,T2>> Zip<T1, T2>

(IEnumerable<T1> first, IEnumerable<T2> second) {

using(var firstEn = first.GetEnumerator())        | [1]

using(var secondEn = second.GetEnumerator()) {  |

while (firstEn.MoveNext() && secondEn.MoveNext()) {    [2]

yield return Tuple.Create(firstEn.Current, secondEn.Current);    [3]

}

}

}

从方法的签名可以看出,参数为两个序列;方法是泛型的,每个输入序列有单独的类型参数。我们使用的是泛型 C# 元组,因此,返回序列包含 Tuple<T1, T2> 类型的元素。在具体实现中,我们首先获得每个序列能够进行遍历元素的枚举器[1],然后,在每个枚举上重复调用 MoveNext 方法,从两个序列中获得下一个元素[2]。如果有一个序列已经结束,我们就产生包含每个枚举器当前元素的元组[3]。

这个示例表明,有时修,处理方法需要显式使用 IEnumerator <T> 接口。foreach 循环为我们提供了从一个源中逐个提取出元素的方法,但是,如果需要从多个源中交替地提取元素,就有问题了。如果我们要在 F# 中实现 Seq.zip,就只能使用相同的方法。既可以在序列表达式中使用 while 循环,也可以使用递归的序列表达式。我们需要的大部分处理函数,在 .NET 和 F# 库中已经有了,所以,我们既可以显式使用,也可以通过使用 C# 的查询表达式语法使用。

时间: 2024-10-04 07:10:36

12.3.1 用迭代器转换序列的相关文章

给出两个单词(start和end)与一个字典,找出从start到end的最短转换序列

问题 给出两个单词(start和end)与一个字典,找出从start到end的最短转换序列.规则如下: 一次只能改变一个字母 中间单词必须在字典里存在 例如: 给出 start = "hit"end = "cog"dict = ["hot","dot","dog","lot","log"] 返回 [ ["hit","hot",&

ADC 转换序列暂时难理解

通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,程序出错的时候理论上都会产生一个core文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决. 相信大多数人都遇到过url出现中文乱码的情况,绝大多数人为了避免出现这种问题,所以设计 url 一般都会尽量设计成都是英文字符.但总避免一种情况就是当你的系统中拥有搜索功能时,你无法预

2014.12.20学习进制转换

进制转换:二进制,八进制,十进制,十六进制. (一)二进制转十进制: 1.写2 2.标指数,从右向左,从0开始依次标记 3.乘系数,一一对应. 4.相加. 例:二进制数1101转十进制数* 1.2   2   2   2 2.2^3   2^2   2^1   2^0 3.1*2^3   1*2^2   0*2^1   1*2^0 4.1*2^3+1*2^2+0*2^1+1*2^0=13 (二)十进制转二进制:除2取余 1.用竖式,对十进制数依次除2,记录每一步余数. 2.一直除到商0为止,从下

Python从菜鸟到高手(12):通过索引操作序列元素

1.定义序列   本文将介绍一下在Python语言中如何定义序列.定义序列的语法与Java中的数组类似,使用一对中括号将序列中的元素值括起来.下面的例子创建一个元素类型是字符串的序列,实现代码如下: names = ["Bill", "Mary", "Jack"]   同一个序列,不仅可以包含相同类型的值,还可以包含不同类型的值.下面的例子在一个序列中放置不同类型的值,实现代码如下: values = ["Bill", 30,

12、SQL Server 行列转换

SQL Server 行转列 在SQL Server 2005中PIVOT 用于将列值转换为列名(行转列),在SQL Server 2000中是没有这个关键字的 只能用case语句实现. --创建测试数据库 use master go if ( exists (select * from sys.databases where name = 'webDB') ) drop database webDB go create database webDB on primary ( name = 'w

给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是: 1,3,4,9,10,12,13,… (该序列实际上就是:3^0,3^1,3^0+3^1,3^2,3^0+3^2,3^1+3^2,3^0+3^1+3^2,…) 请你求出这个序列的第N项的值(用10进制数表示)。 例如,对于k=3,N=100,正确答案应该是9

只有1行,为2个正整数,用一个空格隔开: k N (k.N的含义与上述的问题描述一致,且3≤k≤15,10≤N≤1000). 计算结果,是一个正整数(在所有的测试数据中,结果均不超过2.1*10^9).(整数前不要有空格和其他符号). #include<stdio.h> int n2[1010];long long l1 = 1; long long n, k; long long sm(long long i,long long k) { long long s = 1; int j; fo

有用函数编程

<序> 感谢 关于本书 关于封面 第一部分 学习函数式思维 第一章 不同的思维 1.1 什么是函数式编程? 1.2 通往有用函数编程之路 1.3 用函数式编程提高生产力 1.3.1 函数范式 1.3.2 声明式编程风格 1.3.3 了解程序的执行 1.3.4 设计并发友好的应用程序 1.3.5 函数风格怎样形成代码 1.4 函数式编程演示样例 1.4.1 用声明式风格表达意图 1.4.1.1 用 LINQ 处理数据 1.4.1.2 用 XAML 描写叙述用户界面 1.4.1.3 声明式函数动画

python魔法方法、构造函数、序列与映射、迭代器、生成器

在Python中,所有以__双下划线包起来的方法,都统称为"魔术方法".比如我们接触最多的__init__,魔法方法也就是具有特殊功能的方法. 构造函数 构造函数不同于普通方法,将在对象创建后自动调用它们.也就是在对象创建完成后,自动会调用__init__方法来初始化. 创建一个构造方法 构造方法传参 >>> class FooBar: def __init__(self,value=42): #默认参数 self.somevar = value >>&g

C++14 SFINAE 解引用迭代器

C++14 SFINAE 解引用迭代器 p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 原问题:编写函数f(r),若r为迭代器,则返回f(*r),否则返回r. p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 摘要: p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 问题: 什么是迭代器? 迭代器是