在Haskell中,有一个函数“take n list”,它返回列表中的前n个元素。例如,“sum(take 3 xs)”总结了列表xs中的前三个元素。 F#有同等价值吗?我希望它是List函数之一,但我找不到任何似乎匹配的东西。
答案 0 :(得分:43)
为了澄清一些事情,Seq.take
和Seq.truncate
之间的差异(正如@ sepp2k所指出的)是第二个会给你一个最多返回的序列您指定的元素数量(但如果序列的长度较小,则会减少元素数量。)
如果您尝试访问超出原始列表长度的元素,则生成的序列Seq.take
函数将抛出异常(请注意Seq.take
函数不会立即抛出异常,因为结果是懒惰生成的序列。)
此外,您无需明确地将列表转换为序列。在封面下,list<'a>
是一个.NET类,它继承自seq<'a>
类型,这是一个接口。类型seq<'a>
实际上只是IEnumerable<'a>
的类型别名,因此它由所有其他集合(包括数组,可变列表等)实现。以下代码可以正常工作:
let list = [ 1 .. 10 ]
let res = list |> Seq.take 5
但是,如果要获得类型list<int>
的结果,则需要将序列转换回列表(因为列表的类型比序列更具体):
let resList = res |> List.ofSeq
我不确定为什么F#库不提供List.take
或List.truncate
。我的目标是避免为所有类型的集合重新实现整个函数集,因此在使用更具体的集合类型时,序列的实现足够好的那些仅在Seq
模块中可用(但是这只是我的猜测...)
答案 1 :(得分:15)
是的,它被称为Seq.take
。用法似乎与Haskell的相同:Seq.take
count source 。 要在列表中使用它,请先使用(更新:显然,从评论中,这不是必需的。)List.toSeq
。
答案 2 :(得分:1)
Seq.take正如其他人已经说过的那样有效,但列表上的所有Seq操作都需要付出代价。在Seq.take的情况下,这并不奇怪,因为必须复制列表。
更值得注意的是,例如,列表中的Seq.concat比List.concat需要更多的时间。 我想这意味着你在调用Seq.xxx函数时不只是作为seq访问列表,而是在幕后复制/转换为Seq的列表。 < / p>
编辑:我之所以得出上述结论的原因,是这个使用F#interactive的工作台:
#time "on";;
let lists = [for i in 0..5000000 -> [i..i+1]];;
Seq.length (Seq.concat lists);;
List.length (List.concat lists);;
在我的机器上,List.length
版本需要 1.9秒,而Seq.length
版本需要 3.8秒(最短时间很少重复测试长度线,不包括列表生成线。)