2011-01-13 18 views
7

her n'inci Eleman Alma fakat zarif bir şekilde yapmak için bir yol bulmak görünmüyor. Elbette bir şeyleri hackleyebilirim, ama görmediğim bir kütüphane fonksiyonu var mı diye merak ediyorum. Başka dizisinin her n elemandan oluşan bir diziyi oluşturmak için bir yol arıyorum Bir dizinin

isimler -i bir unsur n'inci bir veya birinin inci (n çoklu) olduğu zaman endam amacıyla oldukça iyi görünüyor sona ama sadece iteri ve mapi, hiçbiri görebilirsiniz dizi fonksiyonları

Bu gerçekten kendini göreve borç veriyor.

Örnek:

let someseq = [1;2;3;4;5;6] 
let partial = Seq.magicfunction 3 someseq 

sonra partial[3;6] olmalıdır. Dışarıda böyle bir şey var mı?

Düzenleme:

let rec thirds lst = 
    match lst with 
    | _::_::x::t -> x::thirds t // corrected after Tomas' comment 
    | _ -> [] 

olacaktır:

Oldukça kadar hırslı değilim ve n bilinen/sabit olduğu için izin verirseniz, o zaman sadece aşağıdaki çalışması gerektiğini tespit ettik Bu kısa yazmanın bir yolu var mı?

+3

' tekrar undecorated tipine bunları map'. –

+0

Listelerinizi kullanarak çözümünüz iyi görünüyor (ama muhtemelen '_ :: _ :: x :: t' (' '_ _ _ _ _ x) yerine' t 'yazmak yerine, tupl'lerin listesini kullanırsınız. 'Seq' listelerinden başka koleksiyonlarla çalışacaktır, ancak bu sizin için bir sorun olmayabilir. Listelerinizdeki sürümünüz güzel ve işlevsel bir koddur. –

+0

Evet, elbette, '_ :: _ :: x :: t', derleyiciyi buraya yapıştırmadan önce sormuş olmalıydı. –

cevap

8

diğer fonksiyonları ile mapi oluştururken davranışı alabilirsiniz: Sadece iki işlevi kullanmak istiyorsunuz Annon önerdiği gibi

let everyNth n seq = 
    seq |> Seq.mapi (fun i el -> el, i)    // Add index to element 
     |> Seq.filter (fun (el, i) -> i % n = n - 1) // Take every nth element 
     |> Seq.map fst        // Drop index from the result 

çözüm kullanarak seçenekler ve choose, ancak ilk birinin vücut biraz daha fazla olacağını karmaşık (ama prensip aslında aynıdır).

let everyNth n (input:seq<_>) = 
    seq { use en = input.GetEnumerator() 
     // Call MoveNext at most 'n' times (or return false earlier) 
     let rec nextN n = 
      if n = 0 then true 
      else en.MoveNext() && (nextN (n - 1)) 
     // While we can move n elements forward... 
     while nextN n do 
      // Retrun each nth element 
      yield en.Current } 

EDIT: Doğrudan IEnumerator nesnesi kullanılarak

Daha verimli versiyonu yazmak için çok zor değil pasajı burada da mevcuttur: http://fssnip.net/1R

+0

Kimin daha hızlı olduğunu bilmiyorsunuz, siz ya da 'Anon', ama ikisi de aynı öneri, öyle değil mi? –

+0

Korkunç derecede verimli değil (kapağın altında 3 yineleyici kullandığı için bazı ek işlev çağrıları ve indirmeler var), ancak çok kötü olmayabilir (ayrılması gereken ara listeler yok). Daha verimli bir versiyon için ya mutasyona ihtiyacınız var (sıralı ifadede) ya da altta yatan 'IEnumerator' –

9

Seq.choose çalışmaları güzel bu durumlarda bunun nedeni mapi lambda içinde filter çalışmasını sağlar. here benzer

let everyNth n elements = 
    elements 
    |> Seq.mapi (fun i e -> if i % n = n - 1 then Some(e) else None) 
    |> Seq.choose id 

.

Daha sonra `Bir` Some` veya `None` içine listenin her elemanını açmak` None`s dışarı filter`, ve `mapi` kullanabilirsiniz
+0

'u kullanın Güzel ve zarif! –

+0

Evet, ben de beğendim! :) –

İlgili konular