2012-02-01 20 views
10

F # içinde 2 listeyi tamamen işlevsel bir şekilde birleştirmeyi düşünüyorum. Sözdizimini anlamakta zorlanıyorum.İki listeyi birleştir

Let, ben eminim yanlış olan var bugüne kadar neden [5;2;3;9;8;4] İşte

olduğunu dönmelidir ben işlevini çağırdığınızda Bir tuple ([5;3;8],[2;9;4])

olduğunu varsayalım. Birisi bunu basit bir şekilde açıklayabilirse minnettar olurdum.

let rec interleave (xs,ys) = function 
|([], ys) -> ys 
|(x::xs, y::ys) -> x :: y:: interleave (xs,ys) 

cevap

11

İşleviniz neredeyse haklı. let f = function, let f x = match x with için kısaltılmıştır, bu nedenle açık hatalara ihtiyacınız yoktur. Ayrıca, algoritmanızın biraz ayarlanması gerekiyor.

let rec interleave = function //same as: let rec interleave (xs, ys) = match xs, ys with 
    |([], ys) -> ys 
    |(xs, []) -> xs 
    |(x::xs, y::ys) -> x :: y :: interleave (xs,ys) 

interleave ([5;3;8],[2;9;4]) //output: [5; 2; 3; 9; 8; 4] 
+1

Teşekkür ama hiçbir tartışma yoktur oldukça neden anlamıyorum. >] Fonksiyonu nasıl arardım? [< – user1072706

+1

Bu işlevi normalde yaptığınız gibi çağırırsınız. Son kod satırı kullanımı gösterir. [Bu MSDN makalesine bakın] (http://msdn.microsoft.com/en-us/library/dd233242.aspx) (sayfanın üstü). İki işlevli (eşdeğer) işlev bildirimi gösterir. – Daniel

8

Önemli bir nokta işlevi doğru olmadığıdır. ([1;2;3], []) girişi ile başarısız olur, çünkü desen eşleştirmesinde (xs, []) durumunu kaçırdınız. Ayrıca, kısmi uygulama ile kullanımı daha kolay olması için argümanlar kıvrılmış formda daha iyidir.

let rec interleave xs ys = 
    match xs, ys with 
    | [], ys -> ys 
    | xs, [] -> xs 
    | x::xs', y::ys' -> x::y::interleave xs' ys' 

Sen özyinelemeli çağrı döndükten sonra iki kez Eksileri (::) yapıcı uygular beri işlevdeğil kuyruk özyinelemeli olduğunu görebilirsiniz: İşte düzeltilmiş versiyonu.

let interleave xs ys = 
    let rec loop xs ys = 
     seq { 
      match xs, ys with 
      | [], ys -> yield! ys 
      | xs, [] -> yield! xs 
      | x::xs', y::ys' -> 
        yield x 
        yield y 
        yield! loop xs' ys' 
      } 
    loop xs ys |> List.ofSeq 
+3

+1 kuyruk-özlü bir çözüm vermek için, şahsen ben bir sıra ifadesinden ziyade devamlılık ya da + 'List.reverse' bir akümülatör kullanmış olurdum. – ildjarn

+1

@ildjarn: [Bu yanıt] 'daki (http://stackoverflow.com/a/7199989/162396) bulgularla ilgilenebilirsiniz (algodan bağımsız olarak tutarlı olma eğilimi gösterirler). Kısacası, bir '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' genellikle, devamlardan daha iyi bir performans gösterir – Daniel

+0

Cool, @Daniel adlı bağlantı için teşekkürler. Süreklilik ve akümülatör + 'List.rev' ilginç olasılıklar, ama ben bu kuyruğu tekrarlayan bir yakın tutmak için' Seq' kullanarak bu sürümü yazdım. – pad

2

Sen daha genel yüksek mertebeden fonksiyonunu tanımlamak için bu fırsatı kullanabilirsiniz - zipWith, ardından kullanmadan interleave uygulamak: Bir ilginç yolu dizisi ifadesini kullanıyor o kuyruk özyinelemeli yapmak.

let rec zipWith f xlist ylist = 
    match f, xlist, ylist with 
    | f, (x :: xs), (y :: ys) -> f x y :: zipWith f xs ys 
    | _, _, _ -> [] 

let interleave xs ys = zipWith (fun a b -> [a; b]) xs ys |> List.concat 

Düzenleme:

@pad Aşağıda belirttiğimiz gibi F # zaten adı List.map2 altında zipWith sahiptir. listelediği Farklı uzunlukta olması durumunda ne olacağına açık değil OP itibaren

let interleave xs ys = List.map2 (fun a b -> [a; b]) xs ys |> List.concat 
+0

'List.map2', Haskell'de" zipWith "ile aynı şeyi yapar. Ve F # listesi tembel değil, bu yüzden 'zipWith' çözümünüzdeki gibi geçici bir liste oluşturacaktır. – pad

+0

@pad, ah, teşekkürler. Daha önce List.map2'yi görmüştüm ama bir şekilde bunu unutmuştum. Ara koleksiyonun oluşturulmasına ilişkin olarak, evet bunun farkındayım, fakat bu “List” deki hemen hemen her yüksek sıra fonksiyonunda geçerli olan bir şey. :-) – missingfaktor

0

, ama burada tam olarak iki listeyi tüketir genel, kuyruk özyinelemeli uygulama var:

// 'a list -> 'a list -> 'a list 
let interleave xs ys = 
    let rec imp xs ys acc = 
     match xs, ys with 
     | [], [] -> acc 
     | x::xs, [] -> imp xs [] (x::acc) 
     | [], y::ys -> imp [] ys (y::acc) 
     | x::xs, y::ys -> imp xs ys (y::x::acc) 
    imp xs ys [] |> List.rev 
aşağıdaki gibi Yani interleave yeniden yazabilirsiniz

Örnekler: hızlı cevap için

> interleave [5;3;8] [2;9;4];; 
val it : int list = [5; 2; 3; 9; 8; 4] 
> interleave [] [1..3];; 
val it : int list = [1; 2; 3] 
> interleave [1..3] [42];; 
val it : int list = [1; 42; 2; 3] 
> interleave [1..3] [42;1337];; 
val it : int list = [1; 42; 2; 1337; 3] 
> interleave [42; 1337] [1..3];; 
val it : int list = [42; 1; 1337; 2; 3] 
İlgili konular