2014-07-03 23 views
5

Koleksiyondan rastgele öğeleri alan, aynı öğenin hiçbir zaman iki kez seçilmeyeceği bir işlev var. Bunun için bir çözüm varClojure'daki bir koleksiyondan n rasgele öğeler nasıl alınır?

(defn take-rand [n coll] 
    (take n (shuffle coll))) 

Ama yani aynı tohum sağlandığında aynı rasgele alt kümesini döndürmek için gereken bir sinir bozucu gereksinimi,

(defn take-rand [n coll & [seed]]) 

(take-rand 5 (range 10) 42L) ;=> (2 5 8 6 7) 
(take-rand 5 (range 10) 42L) ;=> (2 5 8 6 7) 
(take-rand 5 (range 10) 27L) ;=> (7 6 9 1 3) 
(take-rand 5 (range 10))  ;=> (9 7 8 5 0) 

var: Ben oldukça kolay bunu başarabilir , ama biraz aksak ve çok deyimsiz hissediyor. Orada herhangi bir Clojure gazisi iyileştirmeler (veya tamamen farklı bir yaklaşım) önerebilir mi? İşte

ne yaptım:

(defn take-rand 
    "Returns n randomly selected items from coll, or all items if there are fewer than n. 
    No item will be picked more than once." 
    [n coll & [seed]] 
    (let [n (min n (count coll)) 
     rng (if seed (java.util.Random. seed) (java.util.Random.))] 
    (loop [out [], in coll, n n] 
     (if (or (empty? in) (= n 0)) 
     out 
     (let [i (.nextInt rng n)] 
      (recur (conj out (nth in i)) 
       (concat (take i in) (nthrest in (inc i))) 
       (dec n))))))) 
+1

memoize' içindir 'o şey bu değil tam olarak mı bu: Bu çözümü umut

(defn- shuffle' [seed coll] (let [rng (java.util.Random. seed) rnd #(do % (.nextInt rng))] (sort-by rnd coll))) (defn take-rand' ([n coll] (->> coll shuffle (take n))) ([n coll seed] (->> coll (shuffle' seed) (take n)))) 

beklediğiniz sonuçları olun: Size aşağıda benim çözüm gösterecektir sopanın yanlış ucu? Tekerleği yeniden icat etmediğiniz için – peter

cevap

8

Eh, hiçbir Clojure gaziyim, ama yaklaşık nasıl:

(defn shuffle-with-seed 
    "Return a random permutation of coll with a seed" 
    [coll seed] 
    (let [al (java.util.ArrayList. coll) 
     rnd (java.util.Random. seed)] 
    (java.util.Collections/shuffle al rnd) 
    (clojure.lang.RT/vector (.toArray al)))) 

(defn take-rand [n coll & [seed]] 
    (take n (if seed 
       (shuffle-with-seed coll seed) 
       (shuffle coll)))) 

shuffle-with-seed Clojure en shuffle benzerlik gösterir, sadece Random bir örneğini geçer Java'nın java.util.Collections.shuffle().

+2

+1! :) –

+0

İlk testimde birim testleri geçti! –

4

shuffle işlevini, ilk çözümünüzde yeniden üretilebilir olanla değiştirin. - ya bende var

user> (take-rand' 5 (range 10)) 
(5 4 7 2 6) 

user> (take-rand' 5 (range 10)) 
(1 9 0 8 5) 

user> (take-rand' 5 (range 10)) 
(5 2 3 1 8) 

user> (take-rand' 5 (range 10) 42) 
(2 6 4 8 1) 

user> (take-rand' 5 (range 10) 42) 
(2 6 4 8 1) 

user> (take-rand' 5 (range 10) 42) 
(2 6 4 8 1) 
+0

Çok güzel! Çözümünüzün performansını 'java.util.Collections.shuffle() 'kullanan kabul edilen yanıtla test etmeliyim. –

İlgili konular