Finding paths in (DAG) directed acyclic graph given destination - f#

Let's say I have this array:
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
where the first int in a tuple reports to the second int.
I can map that really easily with
let orgMap = Map.ofArray reporting
From there, I could easily get a list of all the ints that report to 2 with
orgMap
|> Map.filter (fun _ key -> key = 2)
which returns
map [(3, 2); (4, 2)]
What I'd really like to see, however, is the entire structure, from 2 all the way down. For example, I'd like to find a way that could give me the sample output
map [(3, 2); (4, 2); (5, 3); (6, 4); (7, 3)]
if I'm looking for person 2 or
map [(5, 3); (7, 3)]
if I'm interested in person 3.
Can I do this? If so, how? Is there another structure other than a map that would be a better way to make this happen?
Thanks in advance for your help.

Since OCaml is close to F# and trying to find Topological sort in F# was not turning up anything useful I looked for OCaml code.
I found An Introduction to Objective Caml which had a solution to your problem using Depth First Search and used it as the basis for this answer. Also because you are new to F# you can review the document and see how the code is derived. Oddly I took a look at the remainder of the document after posting this and he has a more advanced version of DFS latter in the document.
Your input is an array [| |] but your answer is a list [] so I did most of the work as list.
The answers are not in the same order as you had, but they are in the same format.
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
//
// 6 -> 4 -> 2
// 5 -> 3 -> 2 -> 1
// 7 -> 3
// val revStructure : tl:('a * 'b) list -> ('b * 'a) list
let revStructure tl = List.map (fun (a,b) -> (b,a)) tl
// val mem : item:'a -> list:'a list -> bool when 'a : equality
let mem item list = List.exists (fun x -> x = item) list
// val successors : n:'a -> edges:('a * 'b) list -> 'b list when 'a : equality
let successors n edges =
let matching (s,_) = s = n
List.map snd (List.filter matching edges)
// val dist : pred:'a -> succs:'b list -> ('a * 'b) list
let dist pred succs = List.map (fun y -> (pred,y)) succs
// val dfsPairs : edges:('a * 'a) list -> start:'a -> ('a * 'a) list when 'a : equality
let dfsPairs edges start =
let rec dfsPairsInner edges visited start result =
match start with
| [] -> List.rev (revStructure result)
| n::nodes ->
if mem n visited then
dfsPairsInner edges visited nodes result
else
let predecessors = dist n (successors n edges)
let result =
match predecessors with
| [] -> result
| _ -> predecessors # result
dfsPairsInner edges (n::visited) ((successors n edges) # nodes) result
dfsPairsInner edges [] [start] []
let revEdges = revStructure (List.ofArray reportStructure)
let result = dfsPairs revEdges 2
// val result : (int * int) list = [(4, 2); (3, 2); (7, 3); (5, 3); (6, 4)]
let result = dfsPairs revEdges 3
// val result : (int * int) list = [(7, 3); (5, 3)]

I assume that you want to get a list of pair of ints with "numbers" that directly or indirectly report to some "root".
Here is an easy but inefficient solution:
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
let reportStructureSet =
reportStructure |> Set.ofArray
let reportingDirectlyTo root raportsToSet =
raportsToSet
|> Set.filter(fun (_, key) -> key = root)
let addNextGeneration previousIteration raportsToSet =
let numbersLowerInHierarchy = previousIteration |> Set.map fst
raportsToSet |> Set.filter(
// select only those elements from raportsToSet...
fun (num, supervisor) ->
// ...which either are already in previousIteration
(Set.contains (num, supervisor) previousIteration) ||
// ...or are "below" someone from previousIteration
(Set.contains supervisor numbersLowerInHierarchy))
let reportingDirectlyOrIndirectlyTo root raportsToSet =
// applies addNextGeneration until is "stabilizes" on some value
let rec fixPointHelper previousIteration =
let nextIteration = addNextGeneration previousIteration raportsToSet
if nextIteration = previousIteration
then nextIteration
else fixPointHelper nextIteration
// set of numbers directly reporting to root
let reportsDirectly = reportingDirectlyTo root raportsToSet
// start "iteration" using numbers directly reporting to root
fixPointHelper reportsDirectly
let reportingDirectlyOrIndirectlyToList root raportsToSet =
reportingDirectlyOrIndirectlyTo root raportsToSet
|> Set.toList
If you want to implement an efficient solution, you should interpret reportStructureSet as a graph in following way:
ints are vertices
pair of ints are directed edges
Then simply check which edges are reachable from "root" using a DFS.

I like f# puzzles, so I took a stab at this one. I hope that you enjoy.
let orgList = [(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)]
let orgMap =
orgList
|> List.fold (fun acc item ->
let key = snd item
match Map.tryFind key acc with
| Some(value) ->
let map' = Map.remove key acc
Map.add(key) (item::value) map'
| None ->
Map.add(key) (item::[]) acc
) Map.empty<int, (int*int) list>
let findReports supervisor =
let rec findReports' acc collection =
match collection with
| head::tail ->
(findReports' (head::acc) tail)
# match Map.tryFind (fst head) orgMap with
| Some(value) -> (findReports' [] value)
| None -> []
| [] -> acc
findReports' [] (Map.find supervisor orgMap)
findReports 2
|> List.map fst
|> List.distinct
returns
val it : int list = [3; 4; 5; 7; 6]
findReports 2 returns
val it : (int * int) list = [(3, 2); (4, 2); (5, 3); (7, 3); (6, 4)]
I'll break it down to clarify.
let orgList = [ (1, 2); (1, 3); (1, 4); (2, 5); (3, 6); (4, 5); (5, 6); (5, 7) ]
We take your list of tuples and create a functional map of boss to ((report,boss) list). This might be known as an adjacency list, which is used for traversing graphs.
let orgMap =
orgList
|> List.fold (fun acc item ->
let key = snd item
match Map.tryFind key acc with
If there is a list of reports under a boss, add to that list.
| Some(reports) ->
let map' = Map.remove key acc
Map.add(key) (item::reports) map'
Otherwise, add to an empty list and insert into the dictionary.
| None ->
Map.add(key) (item::[]) acc
Start with an empty map as an accumulator.
) Map.empty<int, (int*int) list>
Recurse through the items to find all reports.
let findReports supervisor =
let rec findReports' acc collection =
match collection with
If there is an item, append it to the accumulator. This is BFS. If you switch the expression before and after the concatenate operator (#), it will become DFS.
| head::tail ->
(findReports' (head::acc) tail)
Concatenate the current list to the recursive list of reports to reports.
# match Map.tryFind (fst head) orgMap with
| Some(value) -> (findReports' [] value)
| None -> []
If at the end of the list, return the list.
| [] -> acc
Run the recursive function.
findReports' [] (Map.find supervisor orgMap)
Run the function.
findReports 7
Return only the reports
|> List.map fst
Don't report the report twice.
|> List.distinct

Related

F# convert array to array of tuples

Let's say I have an array
let arr = [|1;2;3;4;5;6|]
I would like to convert it to something like
[|(1,2);(3,4);(5,6)|]
I've seen Seq.window but this one is going to generate something like
[|(1,2);(2,3);(3,4);(4,5);(5,6)|]
which is not what I want
You can use Array.chunkBySize and then map each sub-array into tuples:
let input = [|1..10|]
Array.chunkBySize 2 list |> Array.map (fun xs -> (xs.[0], xs.[1]))
#Slugart's accepted answer is the best approach (IMO) assuming you know that the array has an even number of elements, but here's another approach that doesn't throw an exception if there does happen to be an odd number (it just omits the last trailing element):
let arr = [|1;2;3;4;5|]
seq { for i in 0 .. 2 .. arr.Length - 2 -> (arr.[i], arr.[i+1]) } |> Seq.toArray
You could use Seq.pairwise, as long as you filter out every other tuple. The filtering needs to pass a state through the iteration, which is usually effected by the scan function.
[|1..10|]
|> Seq.pairwise
|> Seq.scan (fun s t ->
match s with None -> Some t | _ -> None )
None
|> Seq.choose id
|> Seq.toArray
// val it : (int * int) [] = [|(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)|]
But then it's also possible to have scan generate the tuples directly, on penalty of an intermediate array.
[|1..10|]
|> Array.scan (function
| Some x, _ -> fun y -> None, Some(x, y)
| _ -> fun x -> Some x, None )
(None, None)
|> Array.choose snd
Use Seq.pairwise to turn a sequence into tuples
[|1;2;3;4;5;6|]
|> Seq.pairwise
|> Seq.toArray
val it : (int * int) [] = [|(1, 2); (2, 3); (3, 4); (4, 5); (5, 6)|]
Should be:
let rec slice =
function
| [] -> []
| a::b::rest -> (a,b) :: slice (rest)
| _::[] -> failwith "cannot slice uneven list"

F#: grouping by recurring sequences of elements

I have a sequence of pairs (key, value) like
[("a", 1), ("a", 2), ("a", 111), ("b", 3), ("bb", 1), ("bb", -1), ...]
, what is the most effective way to convert it into sequence like
[("a", [1,2,111]), ("b", [3]), ("bb", [1,-1])]
or similar?
The sequence has following property: it's really big (>2Gb)
This makes Seq.groupBy really ineffective and incorrect, are there any other ways to do it?
P.S.: this sequence:
[("a", 1), ("a", 2), ("a", 111), ("bb", 1), ("bb", -1), ("a", 5), ("a", 6), ...]
should be converted as
[("a", [1,2,111]), ("bb", [1,-1]), ("a", [5,6]), ...]
--
edit #1: Fixed incorrect sample
edit #2: Sequence is big, so lazy (or fastest) solution is preferred
If you want the option to get lazy results, then I don't think there's an elegant way without maintaining mutable state. Here's a relatively straight-forward one with mutation. You maintain a store of the last key you saw, and all the values that correspond to that:
let s = [("a", 1); ("a", 2); ("a", 111); ("bb", 1); ("bb", -1); ("a", 5); ("a", 6)]
let s2 =
[
let mutable prevKey = None
let mutable values = System.Collections.Generic.List<_>()
let init key value =
prevKey <- Some key
values.Clear()
values.Add value
for (key, value) in s do
match prevKey with
| None -> init key value
| Some k when k = key -> values.Add value
| Some k ->
yield (k, List.ofSeq values)
init key value
match prevKey with
| Some k -> yield (k, List.ofSeq values)
| _ -> ()
]
This gives:
val s2 : (string * int list) list =
[("a", [1; 2; 111]); ("bb", [1; -1]); ("a", [5; 6])]
For lazy evaluation, replace the [ ... ] with seq { ... }
A simple recursive approach with no mutable state.
let rec chunk inseq (accumelem,accumlist) =
match inseq with
|(a,b)::c ->
match accumelem with
|Some(t) -> if t=a then chunk c (accumelem,b::accumlist) else (t,accumlist)::(chunk c (Some(a),b::[]))
|None -> chunk c (Some a,b::[])
|[] ->
match accumelem with
|Some(t) -> (t,accumlist)::[]
|None -> []
chunk [("a", 1); ("a", 2); ("a", 111); ("bb", 1); ("bb", -1); ("a", 5);("a", 6)] (None,[])
val it : (string * int list) list =
[("a", [111; 2; 1]); ("bb", [-1; 1]); ("a", [6; 5])]
Here is a recursive solution:
let test = [("a", 1); ("a", 2); ("a", 111); ("bb", 1); ("bb", -1); ("a", 5); ("a", 6)]
let groupByAdjacentElements alist =
let rec group a groupAcc prevElement adjacentAcc =
match a with
| [] -> match adjacentAcc with
| [] -> groupAcc
| _ -> (prevElement, List.rev adjacentAcc)::groupAcc
| (b, c)::tail -> if b = prevElement then
group tail groupAcc prevElement (c::adjacentAcc)
else
group tail ((prevElement, List.rev adjacentAcc)::groupAcc) b [c]
group alist [] (fst alist.Head) []
|> List.rev
let b = groupByAdjacentElements test
It returns: [("a", [1; 2; 111]); ("bb", [1; -1]); ("a", [5; 6])]
If you want lazy evaluation, you should consider trying LazyList
EDIT: Here's a script comparing LazyList from ExtCore to the accepted solution. It generates a large text file and then does the transformations asked for. Note that the LazyList is returned in reverse order:
open System.Diagnostics
open System.IO
open ExtCore
let fileName = "Test.txt"
let outFile = new StreamWriter(fileName)
for i in [1..20000*300] do
outFile.WriteLine("a,1")
outFile.WriteLine("a,2")
outFile.WriteLine("a,111")
outFile.WriteLine("bb,1")
outFile.WriteLine("bb,-1")
outFile.WriteLine("a,5")
outFile.WriteLine("a,6")
outFile.WriteLine("c,8")
outFile.Close()
printfn "Finished Writing to File"
let data = System.IO.File.ReadLines(fileName)
|> Seq.map (fun i -> let parts = i.Split(',')
(parts.[0], parts.[1]))
printfn "Finished Reading File"
let s2 data =
[
let mutable prevKey = None
let mutable values = System.Collections.Generic.List<_>()
let init key value =
prevKey <- Some key
values.Clear()
values.Add value
for (key, value) in data do
match prevKey with
| None -> init key value
| Some k when k = key -> values.Add value
| Some k ->
yield (k, List.ofSeq values)
init key value
match prevKey with
| Some key -> yield (key, List.ofSeq values)
| _ -> ()
]
let groupByAdjacentElements aseq =
let alist = LazyList.ofSeq aseq
let rec group alist groupAcc prevElement adjacentAcc =
match alist with
| Cons((b, c), tail) ->
if b = prevElement then
group tail groupAcc prevElement (c::adjacentAcc)
else
group tail (LazyList.consDelayed (prevElement, List.rev adjacentAcc) (fun () -> groupAcc)) b [c]
| Nil ->
match adjacentAcc with
| [] -> groupAcc
| _ -> LazyList.consDelayed (prevElement, List.rev adjacentAcc) (fun () -> groupAcc)
group alist LazyList.empty (fst (alist.Head())) []
let groupByAdjacentElementsList aseq =
let alist = aseq |> Seq.toList
let rec group a groupAcc prevElement adjacentAcc =
match a with
| [] -> match adjacentAcc with
| [] -> groupAcc
| _ -> (prevElement, List.rev adjacentAcc)::groupAcc
| (b, c)::tail -> if b = prevElement then
group tail groupAcc prevElement (c::adjacentAcc)
else
group tail ((prevElement, List.rev adjacentAcc)::groupAcc) b [c]
group alist [] (fst alist.Head) []
|> List.rev
[<EntryPoint>]
let main argv =
let stopwatch = new Stopwatch()
stopwatch.Start()
let b = s2 data
printfn "The result is: %A" b
stopwatch.Stop()
printfn "It took %A ms." stopwatch.ElapsedMilliseconds
System.GC.WaitForFullGCComplete() |> ignore
stopwatch.Reset()
stopwatch.Start()
let b = groupByAdjacentElements data
printfn "The result is: %A" b
stopwatch.Stop()
printfn "It took %A ms." stopwatch.ElapsedMilliseconds
System.GC.WaitForFullGCComplete() |> ignore
stopwatch.Reset()
stopwatch.Start()
let b = groupByAdjacentElementsList data
printfn "The result is: %A" b
stopwatch.Stop()
printfn "It took %A ms." stopwatch.ElapsedMilliseconds
0
I when using files of around 300MB in size, LazyList was slightly slower (83s to 94s) than the seq solution. That said LazyList has the major advantage that iterating over it is cached, unlike the sequence solution. The normal list solution was faster than both even when doing List.rev (without it was around 73s).
Grouping by adjacent keys can be also done without mutable bindings. With Seq.scan, it's possible to generate a lazy sequence with eager chunk. It already provides for one of the special cases, the first element of the sequence; by wrapping the input sequence as options followed by None we can take care of the other. Afterwards, we skip over intermediate results and strip out the state with Seq.choose.
For maximum versatility, I'd like to suggest a signature similar to Seq.groupBy,
f:('T -> 'Key) -> xs:seq<'T> -> seq<'Key * 'T list> when 'Key : equality
which takes a key projection function as first argument.
let chunkBy (f : 'T-> 'Key) xs =
// Determine key and wrap in option
seq{for x in xs -> Some(f x, x)
// Indicates end of sequence
yield None }
|> Seq.scan (fun (_, acc, previous) current ->
match previous, current with
| Some(pKey, _), Some(key, value) when pKey = key ->
// No intermediate result, but add to accumulator
None, value::acc, current
| _ ->
// New state is 3-tuple of previous key and completed chunk,
// accumulator from current element, and new previous element
Option.map (fun (k, _) -> k, List.rev acc) previous,
Option.map snd current |> Option.toList, current )
(None, [], None)
|> Seq.choose (fun (result, _, _) -> result)
This can be adopted to OP's requirements by providing also a result projection function.
let chunkBy2 (f : 'T-> 'Key) (g : 'T->'Result) =
chunkBy f >> Seq.map (fun (k, gs) -> k, List.map g gs)
// val chunkBy2 :
// f:('T -> 'Key) -> g:('T -> 'Result) -> (seq<'T> -> seq<'Key * 'Result list>)
// when 'Key : equality
["a", 1; "a", 2; "a", 111; "b", 3; "bb", 1; "bb", -1]
|> chunkBy2 fst snd
// val it : seq<string * int list> =
// seq [("a", [1; 2; 111]); ("b", [3]); ("bb", [1; -1])]
Seq.initInfinite (fun x ->
if (x / 2) % 2 = 0 then "a", x else "b", x)
|> chunkBy2 fst snd
|> Seq.skip 50000
// val it : seq<string * int list> =
// seq
// [("a", [100000; 100001]); ("b", [100002; 100003]); ("a", [100004; 100005]);
// ("b", [100006; 100007]); ...]

F# build a list/array of values + consecutive duplicates

I need to pack data like this:
let data = [1; 2; 2; 3; 2; 2; 2; 4]
let packed = [(1, 1); (2, 2); (3, 1); (2, 3); (4, 1)]
Where each item say how much times it exist before the next. However, it must work with non-adjacent duplications.
I can work this with classical imperative code, but wonder how do this functionally.
Also, Seq.countBy not work because it take in account all the values
If you already have an imperative version, you can follow a set of small steps to refector to a recursive implementation.
Recursion
While I don't know what your imperative version looks like, here's a recursive version:
let pack xs =
let rec imp acc = function
| [] -> acc
| h::t ->
match acc with
| [] -> imp [(h, 1)] t
| (i, count) :: ta ->
if h = i
then imp ((i, count + 1) :: ta) t
else imp ((h, 1) :: (i, count) :: ta) t
xs |> imp [] |> List.rev
This function has the type 'a list -> ('a * int) list when 'a : equality. It uses a private 'implementation function' called imp to do the work. This function is recursive, and threads an accumulator (called acc) throughout. This accumulator is the result list, having the type ('a * int) list.
If the accumulator list is empty, the head of the original list (h), as well as the count 1, is created as a tuple as the only element of the updated accumulator, and the imp function is recursively called with that updated accumulator.
If the accumulator already contains at least one element, the element is extracted via pattern matching, and the element in that tuple (i) is compared to h. If h = i, the accumulator is updated; otherwise, a new tuple is consed on acc. In both cases, though, imp is recursively called with the new accumulator.
You can call it with a list equivalent to your original tuple like this:
> pack [1; 2; 2; 3; 2; 2; 2; 4];;
val it : (int * int) list = [(1, 1); (2, 2); (3, 1); (2, 3); (4, 1)]
Fold
Once you have a recursive version, you often have the recipe for a version using a fold. In this case, since the above pack function has to reverse the accumulator in the end (using List.rev), a right fold is most appropriate. In F#, this is done with the built-in List.foldBack function:
let pack' xs =
let imp x = function
| (i, count) :: ta when i = x -> (i, count + 1) :: ta
| ta -> (x, 1) :: ta
List.foldBack imp xs []
In this case, the function passed to List.foldBack is a bit too complex to pass as an anonymous function, so I chose to define it as a private inner function. It's equivalent to the recursive imp function used by the above pack function, but you'll notive that it doesn't have to call itself recursively. Instead, it just has to return the new value for the accumulator.
The result is the same:
> pack' [1; 2; 2; 3; 2; 2; 2; 4];;
val it : (int * int) list = [(1, 1); (2, 2); (3, 1); (2, 3); (4, 1)]
My solution assumes the data collection is a list. If having it as a tuple (as per your example) was intentional then for my solution to work the tuple has to be converted to a list (an example how to do it can be found here).
let groupFunc list =
let rec groupFuncRec acc lst init count =
match lst with
| [] -> List.rev acc
| head::[] when head = init
-> groupFuncRec ((init, count)::acc) [] 0 0
| head::[] when head <> init
-> groupFuncRec ((head, 1)::acc) [] 0 0
| head::tail when head = init
-> groupFuncRec acc tail head (count+1)
| head::tail when head <> init
-> groupFuncRec ((init, count)::acc) tail head 1
let t = List.tail list
let h = List.head list
groupFuncRec [] t h 1
When I run the function on your sample data I get back the expected result:
list = [(1, 1); (2, 2); (3, 1); (4, 1)]
You can get Seq.countBy to work by including some positional information in its argument. Of course, you need then to map back to your original data.
[1; 2; 2; 3; 2; 2; 2; 4]
|> Seq.scan (fun (s, i) x ->
match s with
| Some p when p = x -> Some x, i
| _ -> Some x, i + 1 ) (None, 0)
|> Seq.countBy id
|> Seq.choose (function
| (Some t, _), n -> Some(t, n)
| _ -> None )
|> Seq.toList
// val it : (int * int) list = [(1, 1); (2, 2); (3, 1); (2, 3); (4, 1)]

F# -> Fold with 2 parameters

I'm trying to make a custom fold which goes through my sequence, and takes 2 Teams a time and assign them to a Match and then return a Match list in the end.
My current code is:
let myFold f s =
let rec myFold' f s acc =
match s with
| (a1::a2::a) -> f a1 a2::acc
| _ -> acc
myFold' f s []
Which gives me (int -> int) list
But obviously thats not going to work... What am I doing wrong?
-> I know that I just can create a recrusive function special made for this scenario, however I want to make it so abstract as possible for reuse.
Im' not quite sure that I get what you want to achieve. From sequence [1;2;3;4] you want to get [(1,2); (3,4)] or [(1,2); (2,3); (3,4)] ?
let fold f s =
let rec impl acc = function
| x::y::rest -> impl ((f x y)::acc) rest
| _ -> List.rev acc
impl [] s
let s = [1;2;3;4;5;6]
let r = fold (fun x y -> x,y) s // [(1, 2); (3, 4); (5, 6)]
let fold2 f s = Seq.pairwise s |> Seq.map f |> Seq.toList
let r2 = fold2 id s // [(1, 2); (2, 3); (3, 4); (4, 5); (5, 6)]

F# return element pairs in list

I have been looking for an elegant way to write a function that takes a list of elements and returns a list of tuples with all the possible pairs of distinct elements, not taking into account order, i.e. (a,b) and (b,a) should be considered the same and only one of them be returned.
I am sure this is a pretty standard algorithm, and it's probably an example from the cover page of the F# documentation, but I can't find it, not even searching the Internet for SML or Caml. What I have come up with is the following:
let test = [1;2;3;4;5;6]
let rec pairs l =
seq {
match l with
| h::t ->
yield! t |> Seq.map (fun elem -> (h, elem))
yield! t |> pairs
| _ -> ()
}
test |> pairs |> Seq.toList |> printfn "%A"
This works and returns the expected result [(1, 2); (1, 3); (1, 4); (1, 5); (1, 6); (2, 3); (2, 4); (2, 5); (2, 6); (3, 4); (3, 5); (3, 6); (4, 5); (4, 6); (5, 6)] but it looks horribly unidiomatic.
I should not need to go through the sequence expression and then convert back into a list, there must be an equivalent solution only involving basic list operations or library calls...
Edited:
I also have this one here
let test = [1;2;3;4;5;6]
let rec pairs2 l =
let rec p h t =
match t with
| hx::tx -> (h, hx)::p h tx
| _ -> []
match l with
| h::t -> p h t # pairs2 t
| _ -> []
test |> pairs2 |> Seq.toList |> printfn "%A"
Also working, but like the first one it seems unnecessarily involved and complicated, given the rather easy problem. I guess my question is mor about style, really, and if someone can come up with a two-liner for this.
I think that your code is actually pretty close to an idiomatic version. The only change I would do is that I would use for in a sequence expression instead of using yield! in conjunction with Seq.map. I also usually format code differently (but that's just a personal preference), so I would write this:
let rec pairs l = seq {
match l with
| h::t -> for e in t do yield h, elem
yield! pairs t
| _ -> () }
This is practically the same thing as what Brian posted. If you wanted to get a list as the result then you could just wrap the whole thing in [ ... ] instead of seq { ... }.
However, this isn't actually all that different - under the cover, the compiler uses a sequence anyway and it just adds conversion to a list. I think that it may be actually a good idea to use sequences until you actually need a list (because sequences are evaluated lazilly, so you may avoid evaluating unnecessary things).
If you wanted to make this a bit simpler by abstracting a part of the behavior into a separate (generally useful) function, then you could write a function e.g. splits that returns all elements of a list together with the rest of the list:
let splits list =
let rec splitsAux acc list =
match list with
| x::xs -> splitsAux ((x, xs)::acc) xs
| _ -> acc |> List.rev
splitsAux [] list
For example splits [ 1 .. 3 ] would give [(1, [2; 3]); (2, [3]); (3, [])]. When you have this function, implementing your original problem becomes much easier - you can just write:
[ for x, xs in splits [ 1 .. 5] do
for y in xs do yield x, y ]
As a guide for googling - the problem is called finding all 2-element combinations from the given set.
Here's one way:
let rec pairs l =
match l with
| [] | [_] -> []
| h :: t ->
[for x in t do
yield h,x
yield! pairs t]
let test = [1;2;3;4;5;6]
printfn "%A" (pairs test)
You seem to be overcomplicating things a lot. Why even use a seq if you want a list? How about
let rec pairs lst =
match lst with
| [] -> []
| h::t -> List.map (fun elem -> (h, elem)) t # pairs t
let _ =
let test = [1;2;3;4;5;6]
printfn "%A" (pairs test)

Resources