как получить пары последовательных значений из F # Seq - PullRequest
7 голосов
/ 08 ноября 2010

У меня есть последовательность с {"1";"a";"2";"b";"3";"c";...}.

Как я могу преобразовать этот seq в {("1","a");("2","b");("3","c");...}

Ответы [ 6 ]

17 голосов
/ 08 ноября 2010

Вот слишком умное решение:

let s = ["1";"a";"2";"b";"3";"c"]

let pairs s =
    s |> Seq.pairwise 
      |> Seq.mapi (fun i x -> i%2=0, x) 
      |> Seq.filter fst 
      |> Seq.map snd

printfn "%A" (pairs s)
10 голосов
/ 09 ноября 2010

Счетчики не всегда злые.

let pairs (source: seq<_>) =
    seq { 
        use iter = source.GetEnumerator() 
        while iter.MoveNext() do
            let first = iter.Current
            if iter.MoveNext() then
                let second = iter.Current 
                yield (first, second)
    }

Вот исходный код F # Seq.pairwise, взятый из FSharp.Core/seq.fs

[<CompiledName("Pairwise")>]
let pairwise (source: seq<'T>) = //'
    checkNonNull "source" source
    seq { use ie = source.GetEnumerator() 
          if ie.MoveNext() then
              let iref = ref ie.Current
              while ie.MoveNext() do
                  let j = ie.Current 
                  yield (!iref, j)
                  iref := j }
3 голосов
/ 16 декабря 2016

Начиная с F # 4.0, теперь вы можете использовать chunkBySize

let source = seq ["1";"a";"2";"b";"3";"c"]

let pairs source =
    source
    |> Seq.chunkBySize 2
    |> Seq.map (fun a -> a.[0], a.[1])

;;
printfn "%A" (pairs source)
1 голос
/ 12 ноября 2010

Вы можете использовать LazyLists для этого.

let (|Cons|Nil|) = LazyList.(|Cons|Nil|)

let paired items =
    let step = function
        | Cons(x, Cons(y, rest)) ->
            Some((x, y), rest)
        | _ ->
            None
    Seq.unfold step (LazyList.ofSeq items)
0 голосов
/ 09 ноября 2010

Вот вариант решения @ Брайана:

["1";"a";"2";"b";"3";"c";"4";"d";"5";"e";"6";"f"]
|> Seq.pairwise
|> Seq.mapi (fun i x -> if i%2=0 then Some(x) else None)
|> Seq.choose id

А вот расплавитель мозгов, использующий Seq.scan:

["1";"a";"2";"b";"3";"c";"4";"d";"5";"e";"6";"f"]
|> Seq.scan (fun ((i,prev),_) n -> match prev with
                                   | Some(n') when i%2=0 -> ((i+1,Some(n)), Some(n',n))
                                   | _ -> ((i+1,Some(n)), None))
            ((-1,None), None)
|> Seq.choose snd
0 голосов
/ 08 ноября 2010

Вы можете использовать сопоставление с образцом следующим образом:

let list = ["1";"2";"3";"4";"5";"6"]

let rec convert l =
    match l with
        x :: y :: z -> (x,y) :: convert z
        | x :: z -> (x,x) :: convert z
        | [] -> []

let _ = 
  convert list

, но вы должны решить, что делать, если список содержит нечетное количество элементов (в моем решении получается пара с таким же значением)

...