2010-11-08 12 views
6

Ho una sequenza con {"1";"a";"2";"b";"3";"c";...}.come ottenere coppie di valori consecutivi da F # Seq

Come posso trasformare questa ss in {("1","a");("2","b");("3","c");...}

+0

Ecco una risposta correlata che potrebbe interessarti: http://stackoverflow.com/questions/833180/handy-f-snippets/2271132 # 2271132, sebbene sia per le liste, non per Seq. – Benjol

risposta

0

È possibile utilizzare il pattern matching nel seguente modo:

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 

ma si deve decidere che cosa fare se la lista ha un numero dispari di elementi (nella mia soluzione coppia con lo stesso valore è prodotto)

+0

(Non so se ci sono costrutti intelligenti in F #, sono abituato a OCaml :) – Jack

+0

questo funzionerebbe se fosse una lista ma ho un seq molto grande. Non sono sicuro se questo approccio di pattern matching funzionerà su un Seq – functional

+0

perché non dovrebbe funzionare? Passa attraverso l'elenco e costruisce il nuovo concatenando. Dovrebbe essere una complessità lineare .. o sei preoccupato per l'overflow dello stack? – Jack

15

Ecco una soluzione molto troppo intelligente:

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

Gli enumeratori non sono sempre cattivi.

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

Ecco il codice # source F di Seq.pairwise preso da 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

"Gli enumeratori non sono sempre cattivi" +1 a quello . – AruniRC

0

Ecco una variazione sul @ soluzione di 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 

Ed ecco un cervello-fusore utilizzando 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

Per questo potresti prendere in considerazione l'utilizzo di LazyList.

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

Dal F # 4.0, è ora possibile utilizzare 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) 
Problemi correlati