Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does Seq.isEmpty say not enough elements?

Tags:

f#

nums is indeed seq of int when I mouse over. Any idea what's going on? This function line is intended to be the equivalent of C#'s DefaultIfEmpty Linq function.

The general idea is take a space delimited line of strings and write out which ones occur count number of times.

enter image description here

code:

    open System

[<EntryPoint>]
let main argv = 
    let tests = Console.ReadLine() |> int
    for i in [0..tests] do
        let (length, count) = Console.ReadLine() 
                                |> (fun s -> s.Split [|' '|])
                                |> (fun split -> Int32.Parse(split.[0]), Int32.Parse(split.[1]))
        Console.ReadLine() 
            |> (fun s -> s.Split [|' '|])
            |> Seq.map int 
            |> Seq.take length
            |> Seq.groupBy (fun x -> x)     
            |> Seq.map (fun (key, group) -> key, Seq.sum group)
            |> Seq.where (fun (_, countx) -> countx = count)
            |> Seq.map (fun (n, _) -> n)
            |> (fun nums -> if Seq.isEmpty nums then "-1" else String.Join(" ", nums))
            |> Console.WriteLine

    0 // return an integer exit code

Sample input:
3
9 2
4 5 2 5 4 3 1 3 4

like image 696
Michael DiLeo Avatar asked Jan 07 '23 18:01

Michael DiLeo


1 Answers

So, sequences in F# use lazy evaluation. That means that when you use functions such as map, where, take etc, the results are not evaluated immediately.

The results are only evaluated when the sequence is actually enumerated. When you call Seq.isEmpty you trigger a call to MoveNext() which results in the first element of the result sequence being evaluated - in your case this results in a large chain of functions being evaluated.

In this case, the InvalidOperationException is actually being triggered by Seq.take which throws if the sequence doesn't have sufficient elements. This might surprise you coming from C# where Enumerable.Take will take up to the requested number of elements but could take fewer if you reach the end of the sequence.

If you want this behaviour in F#, you need to replace Seq.take with Seq.truncate.

like image 191
TheInnerLight Avatar answered Jan 11 '23 17:01

TheInnerLight