Take N elements from sequence with N different indexes in F#

后端 未结 4 1366
清酒与你
清酒与你 2021-01-18 01:50

I\'m new to F# and looking for a function which take N*indexes and a sequence and gives me N elements. If I have N indexes it should be equal to concat Seq.nth index0, Seq.n

4条回答
  •  梦谈多话
    2021-01-18 02:29

    When you want to access elements by index, then using sequences isn't as good idea. Sequences are designed to allow sequential iteration. I would convert the necessary part of the sequence to an array and then pick the elements by index:

    let takeIndexes ns input = 
      // Take only elements that we need to access (sequence could be infinite)
      let arr = input |> Seq.take (1 + Seq.max ns) |> Array.ofSeq
      // Simply pick elements at the specified indices from the array
      seq { for index in ns -> arr.[index] }
    
    seq [10 .. 20] |> takeIndexes [0;5;10]  
    

    Regarding your implementation - I don't think it can be made significantly more elegant. This is a general problem when implementing functions that need to take values from multiple sources in an interleaved fashion - there is just no elegant way of writing those!

    However, you can write this in a functional way using recursion like this:

    let takeIndexes indices (xs:seq) = 
      // Iterates over the list of indices recursively
      let rec loop (xe:IEnumerator<_>) idx indices = seq {
        let next = loop xe (idx + 1)
        // If the sequence ends, then end as well
        if xe.MoveNext() then
          match indices with
          | i::indices when idx = i -> 
            // We're passing the specified index 
            yield xe.Current
            yield! next indices
          | _ -> 
            // Keep waiting for the first index from the list
            yield! next indices }
      seq {
        // Note: 'use' guarantees proper disposal of the source sequence
        use xe = xs.GetEnumerator()
        yield! loop xe 0 indices }
    
    seq [10 .. 20] |> takeIndexes [0;5;10]  
    

提交回复
热议问题