这是一个非常简单的问题,但我找不到答案:
在F#中是否有任何Seq/List操作来匹配LINQ SelectMany?
但是,如果我试图证明F#List操作比LINQ更强大......
在C#SelectMany使用语法非常简单:
var flattenedList = from i in items1
from j in items2
select ...
Run Code Online (Sandbox Code Playgroud)
有没有简单的直接匹配,List.flatten,List.bind或类似的东西?
SelectMany有几个签名,但最复杂的签名似乎是:
IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TCollection>> collectionSelector,
Func<TSource, TCollection, TResult> resultSelector
);
Run Code Online (Sandbox Code Playgroud)
在F#术语中,这将是:
('a -> 'b list) -> ('a -> 'b -> 'c) -> 'a list -> 'c list
Run Code Online (Sandbox Code Playgroud)
gra*_*bot 31
collect是SelectMany的F#等价物,但它不提供所有重载.以下是如何制作您引用的那个.
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>
Run Code Online (Sandbox Code Playgroud)
我相信F#不提供所有SelectMany重载,因为它们会向库中添加噪声.以下是Microsoft Naming中SelectMany的所有四次重载.
let selectMany (source : 'TSource seq) (selector : 'TSource -> 'TResult seq) =
source |> Seq.collect selector
let selectMany (source : 'TSource seq) (selector : 'TSource -> int -> 'TResult seq) =
source |> Seq.mapi (fun n s -> selector s n) |> Seq.concat
let selectMany (source : 'TSource)
(collectionSelector : 'TSource -> 'TCollection seq)
(resultSelector : 'TSource -> 'TCollection -> 'TResult) =
source
|> Seq.collect (fun sourceItem ->
collectionSelector sourceItem
|> Seq.map (fun collection -> resultSelector sourceItem collection))
let selectMany (source : 'TSource)
(collectionSelector : 'TSource -> int -> 'TCollection seq)
(resultSelector : 'TSource -> 'TCollection -> 'TResult) =
source
|> Seq.mapi (fun n sourceItem ->
collectionSelector sourceItem n
|> Seq.map (fun collection -> resultSelector sourceItem collection))
|> Seq.concat
Run Code Online (Sandbox Code Playgroud)
"F#List操作比LINQ更强大......"虽然seq/list操作很棒但是一些真正的"F#power"来自Function Composition和Currying.
// function composition
let collect selector = Seq.map selector >> Seq.concat
Run Code Online (Sandbox Code Playgroud)
Tho*_*que 11
您可以使用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]))
Run Code Online (Sandbox Code Playgroud)
这大致相当于以下C#代码:
var flat = from i1 in items1
from i2 in items2
select new { i1, i2 };
Run Code Online (Sandbox Code Playgroud)
其他帖子显示了如何匹配linq
从这个linq开始:
var flattenedList = from i in items1
from j in items2
select ...
var flattenedList2 = items1.SelectMany(i => items2.Map(j => ...))
Run Code Online (Sandbox Code Playgroud)
等价的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 -> ...))
Run Code Online (Sandbox Code Playgroud)
两位代码在表达性和复杂性方面大致相同.
话虽如此,让我们在你的帖子中提出一个具体的评论:
但是,如果我试图证明F#List操作比LINQ更强大......
Seq/List模块中的操作大致相当于Enumerable/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)]
Run Code Online (Sandbox Code Playgroud)
这在C#中重新实现会有点尴尬,但是编写F#很简单.