Thomas
Thomas

Reputation: 12107

Combining 2 lists in F#

I have 2 lists with coordinates (one per axis) and I'm making squares out of them:

// create all combinations
let squares = List<int * int * int * int>()
seqX
|> Seq.pairwise
|> Seq.iter (fun (x1, x2) ->
    seqY
    |> Seq.pairwise
    |> Seq.iter (fun (y1, y2) -> squares.Add(x1, y1, x2, y2))
)

Is there a way, using the collection functions to make this? I can't use Seq.map because the output will not match the total number of iterations

|> Seq.map (fun (y1, y2) -> (x1, y1, x2, y2))

will not work

Upvotes: 1

Views: 115

Answers (1)

Asti
Asti

Reputation: 12667

You could use Seq.collect to flat-map an inner sequence.

Collect (aka SelectMany in LINQ, and flatMap in JS) projects each item onto a new sequence, and flattens the results.

   seqX 
   |> Seq.pairwise 
   |> Seq.collect(fun (x1, x2) -> seqY |> Seq.map(fun (y1, y2) -> (x1, x2, y1, y2))

Or you could make a sequence expression to do it for you, which de-sugars to the above:

 seq {
    for (x1, x2) in seqX |> Seq.pairwise do
    for (y1, y2) in seqY |> Seq.pairwise do
    yield (x1, x2, y1, y2) 
 }

Sequence expressions are very useful when there is depth involved. It's much cleaner than writing nested closures for every level (seq |> Seq.collect (fun _ -> Seq.collect(fun...).

Here's an example which finds all right-angled triangles whose sides are less than 10, by going through every possible triangle and checking Pythagoras' theorem.

 seq {
    let sides = [1..10]   
    for a in sides do
    for b in sides do
    for c in sides do
    if a * a + b * b = c * c then
        yield (a, b, c) 
 }

This would be much uglier de-sugared.

Upvotes: 5

Related Questions