F# F列表SelectMany
这是一个非常简单的问题,但我没有找到答案: F中是否有任何Seq/List操作来匹配LINQ SelectMany 我知道我可以使用System.Linq in F,如果我 想。 我知道我可以做一个递归方法 并使用F计算表达式 制造更强大的东西。 但如果我试图证明F列表运算比LINQ更强大 .Where=List.filter .Select=List.map .Aggregate=List.fold ... 在C语言中,许多用法的语法非常简单:F# F列表SelectMany,f#,linq,F#,Linq,这是一个非常简单的问题,但我没有找到答案: F中是否有任何Seq/List操作来匹配LINQ SelectMany 我知道我可以使用System.Linq in F,如果我 想。 我知道我可以做一个递归方法 并使用F计算表达式 制造更强大的东西。 但如果我试图证明F列表运算比LINQ更强大 .Where=List.filter .Select=List.map .Aggregate=List.fold ... 在C语言中,许多用法的语法非常简单: var flattenedList = from
var flattenedList = from i in items1
from j in items2
select ...
有没有简单的直接匹配,List.flatte,List.bind之类的
SelectMany有几个签名,但最复杂的似乎是:
IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TCollection>> collectionSelector,
Func<TSource, TCollection, TResult> resultSelector
);
Seq.bind就是你想要的。SelectMany实际上只是一个一元绑定:
所以你会这样做:
seq { for i in items1 do
for j in items2 do
yield .... };
您可以使用List.collect或Seq.collect:
let items1 = [1; 2; 3]
let items2 = [4; 5; 6]
let flat = items1 |> List.collect (fun i1 -> items2 |> List.map (fun i2 -> [i1, i2]))
这大致相当于以下C代码:
var flat = from i1 in items1
from i2 in items2
select new { i1, i2 };
collect相当于SelectMany,但它不提供所有重载。下面是如何制作您引用的一个
let selectMany (ab:'a -> 'b seq) (abc:'a -> 'b -> 'c) input =
input |> Seq.collect (fun a -> ab a |> Seq.map (fun b -> abc a b))
// gives
// val selectMany : ('a -> seq<'b>) -> ('a -> 'b -> 'c) -> seq<'a> -> seq<'c>
F列表操作比LINQ更强大。。。虽然seq/list操作很棒,但一些真正的F能力来自和
其他帖子展示了如何将linq与 从这个linq开始:
var flattenedList = from i in items1
from j in items2
select ...
var flattenedList2 = items1.SelectMany(i => items2.Map(j => ...))
等效F为:
let flattenedList = seq {
for a in items1 do
for b in items2 do
yield ... }
let flattenedList2 = items1 |> Seq.collect (fun i -> items2 |> Seq.map (fun j -> ...))
这两位代码在表达能力和复杂性上大致相当
话虽如此,让我们在您的帖子中发表一条具体评论:
但如果我试图证明F列表
行动比行动更强大
林克
Seq/List模块中的操作大致相当于可枚举/Linq扩展
然而,我要说的是,列表的杀手级功能是能够对它们进行模式匹配。下面是一个不容易转换为linq的愚蠢示例:
let rec funky = function
| x::y::z::rest -> (z, y)::funky(z::x::rest)
| [y;z]-> [(z, y)]
| [z] -> [(z, z)]
| [] -> []
// funky [1..6]
// = (int * int) list = [(3, 2); (4, 1); (5, 3); (6, 4)]
这在C中重新实现会有点尴尬,但是编写F非常简单。有很多好的选项可以创建自己的SelectMany,但是直接使用SelectMany呢
let flatten (source : 'T seq seq) :'T seq =
System.Linq.Enumerable.SelectMany(source, id)
这是对使用F的.net SelectMany的基本调用。如何显示F列表比C列表更强大?如果这是一个问题,其中一个有更多的功能,这并不表明更强大,只是更臃肿。你是不是在试图用列表来证明你在F中可以做一些用C做不到的事情?我在F库或powerpack中都没有看到Seq.bind。你是说Seq.collect吗?你没有看到Seq.bind,因为它不是Seq模块中的函数;这是seq monoid下面的工作流生成器的一种方法。@pblasucci:原则上是的,但seq{..}不是真正的计算表达式。它是由编译器专门处理的,seq并不是一个真正的计算生成器,它只是一个函数seq。因此,Seq.collect是正确的答案,但它并没有真正用于序列表达式的编译形式SelectMany@Tomas:谢谢你的澄清。seq的特殊情况处理是因为它发生得如此频繁,因此需要特殊优化吗?
let flattenedList = seq {
for a in items1 do
for b in items2 do
yield ... }
let flattenedList2 = items1 |> Seq.collect (fun i -> items2 |> Seq.map (fun j -> ...))
let rec funky = function
| x::y::z::rest -> (z, y)::funky(z::x::rest)
| [y;z]-> [(z, y)]
| [z] -> [(z, z)]
| [] -> []
// funky [1..6]
// = (int * int) list = [(3, 2); (4, 1); (5, 3); (6, 4)]
let flatten (source : 'T seq seq) :'T seq =
System.Linq.Enumerable.SelectMany(source, id)