Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# List SelectMany

Tags:

linq

f#

This is quite simple question but I didn't find an answer:

Is there any Seq/List operation in F# to match the LINQ SelectMany?

  • I know I can use System.Linq in F# if I want to.
  • I know I can make a recursive method and use F# Computation Expressions (and make even more powerful things).

But if I try to prove that F# List operations are more powerful than LINQ...

  • .Where = List.filter
  • .Select = List.map
  • .Aggregate = List.fold
  • ...

In C# SelectMany usage syntax is pretty simple:

var flattenedList = from i in items1                     from j in items2                     select ... 

Is there any easy direct match, List.flatten, List.bind or something like that?

SelectMany has a couple of signatures, but the most complex one seems to be:

IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(     this IEnumerable<TSource> source,      Func<TSource, IEnumerable<TCollection>> collectionSelector,      Func<TSource, TCollection, TResult> resultSelector ); 

In F# terms this would be:

('a -> 'b list) -> ('a -> 'b -> 'c) -> 'a list -> 'c list 
like image 252
Tuomas Hietanen Avatar asked Jan 04 '11 23:01

Tuomas Hietanen


1 Answers

collect is the F# equivalent of SelectMany however it doesn't provide all the overloads. Here's how to make the one you referenced.

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> 

I believe F# doesn't provide all the SelectMany overloads because they would add noise to the library. Here's all four overloads to SelectMany in Microsoft Naming.

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 

"F# List operations are more powerful than LINQ..." While seq / list operations are great some real "F# power" comes from Function Composition and Currying.

// function composition let collect selector = Seq.map selector >> Seq.concat 
like image 161
gradbot Avatar answered Oct 11 '22 09:10

gradbot