2010-11-08 7 views
6

Tengo una secuencia con {"1";"a";"2";"b";"3";"c";...}.cómo obtener pares de valores consecutivos de F # Seq

¿Cómo puedo transformar esta ss en {("1","a");("2","b");("3","c");...}

+0

Aquí es una respuesta relacionada que pueden interesarle: http://stackoverflow.com/questions/833180/handy-f-snippets/2271132 # 2271132, aunque es para listas, no para Seq. – Benjol

Respuesta

0

Puede utilizar concordancia con el modelo de la siguiente manera:

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 

pero usted tiene que decidir qué hacer si la lista tiene un número impar de elementos (en mi solución se produce de un par con mismo valor)

+0

(No sé si hay construcciones inteligentes en F #, estoy acostumbrado a OCaml :) – Jack

+0

esto funcionaría si fuera una lista, pero tengo una secuencia muy grande. no estoy seguro de si este enfoque de coincidencia de patrones funcionará en una secuencia – functional

+0

¿por qué no debería funcionar? Pasa por la lista y crea la nueva por concatenación. Debería ser una complejidad lineal ... ¿o le preocupa el desbordamiento de pila? – Jack

15

Aquí es una solución mucho-demasiado-inteligente:

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) 
+0

sublime ........ – Indy9000

10

Los enumeradores no siempre son malvados.

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) 
    } 

Aquí está el código # fuente F del Seq.pairwise tomado de 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 } 
+0

"Los enumeradores no siempre son malvados" +1 a ese . – AruniRC

0

Aquí hay una variación en @ solución de Brian:

["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 

Y aquí está un cerebro-fusor con 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 
1

Puede considerar el uso de LazyLists para esto.

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) 
2

Como F # 4.0, ahora se puede utilizar 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) 
Cuestiones relacionadas