2013-02-12 28 views
8

मैं सेट जो एक ही हर बार मेरा कार्यक्रम चलाया जाता है हो जाएगा के कुछ शफ़ल करना चाहते हैं:क्या मैं क्लोजर में एक निर्धारित शफल कर सकता हूं?

यह एक तरीका है यह करने के लिए है:

(def colours ["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"]) 

(defn colour-shuffle [n] 
    (let [cs (nth (clojure.math.combinatorics/permutations colours) n)] 
    [(first cs) (drop 1 cs)])) 

; use (rand-int 40320) to make up numbers, then hard code: 
(def colour-shuffle-39038 (colour-shuffle 39038)) 
(def colour-shuffle-28193 (colour-shuffle 28193)) 
(def colour-shuffle-5667 (colour-shuffle 5667)) 
(def colour-shuffle-8194 (colour-shuffle 8194)) 
(def colour-shuffle-13895 (colour-shuffle 13895)) 
(def colour-shuffle-2345 (colour-shuffle 2345)) 

colour-shuffle-39038 ; ["white" ("magenta" "blue" "green" "cyan" "yellow" "red" "black")] 

लेकिन यह मूल्यांकन करने के लिए कुछ समय लगता है , और अपर्याप्त और बल्कि सुरुचिपूर्ण लगता है।

क्या सभी अनुक्रमों को उत्पन्न और उपभोग किए बिना सीधे शफल 3 9 038 उत्पन्न करने का कोई तरीका है?

(मैं पहले से ही पता है कि मैं कड़ी मेहनत उन्हें कोड कर सकते हैं, या प्रयास को वापस लाने के लिए मैक्रो के साथ समय संकलित करने के लिए भी एक सा बकवास लगता है यही कारण है कि।।)

+5

: clojure.core/shuffle इस तर्क का उपयोग नहीं है, लेकिन आप इसका इस्तेमाल फेरबदल का एक परिवर्तन है कि एक अतिरिक्त बीज मूल्य तर्क लेता बनाने के लिए कर सकता है, और एक यादृच्छिक संख्या जनरेटर बनाने के लिए है कि बीज मान का उपयोग java.util.Collection/shuffle को पारित करने के लिए फिशर-येट्स जैसे मानक शफल एल्गोरिदम का उपयोग कर सकते हैं लेकिन आरएनजी –

+0

माइक के लिए बीज तर्क जोड़ सकते हैं, हां, यही वह है जो मैं सोच रहा था। क्या क्लोजर में से कोई एक या उसके libs में से एक है या क्या मुझे एक कोड कोड करना है? –

+1

लगता है जैसे आप पूछ रहे हैं कि क्या आप संख्या क्रमपरिवर्तन कर सकते हैं और इससे पहले 'n-1' उत्पन्न किए बिना 'nth' चुनें।हां, आप इसे [लेमर कोड का डीकोडिंग] लागू करके करते हैं (http://en.wikipedia.org/wiki/Permutation#Numbering_permutations)। मैंने अपने जवाब में इस पर एक झटका लगाया है। –

उत्तर

3

लगता है कि आपने number permutations हैं:

(def factorial (reductions * 1 (drop 1 (range)))) 

(defn factoradic [n] {:pre [(>= n 0)]} 
    (loop [a (list 0) n n p 2] 
     (if (zero? n) a (recur (conj a (mod n p)) (quot n p) (inc p))))) 

(defn nth-permutation [s n] {:pre [(< n (nth factorial (count s)))]} 
    (let [d (factoradic n) 
     choices (concat (repeat (- (count s) (count d)) 0) d)] 
    ((reduce 
     (fn [m i] 
      (let [[left [item & right]] (split-at i (m :rem))] 
      (assoc m :rem (concat left right) 
        :acc (conj (m :acc) item)))) 
     {:rem s :acc []} choices) :acc))) 

की यह कोशिश करते हैं:

(def colours ["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"]) 

(nth-permutation colours 39038) 
=> ["white" "magenta" "blue" "green" "cyan" "yellow" "red" "black"] 

... प्रश्न में के रूप में है, लेकिन अन्य क्रमपरिवर्तन की किसी भी पैदा करने के बिना।

काफी अच्छा है, लेकिन क्या हम उन्हें सब मिलेंगे?

(def x (map (partial nth-permutation colours) (range (nth factorial (count colours))))) 

(count x) 
=> 40320 
(count (distinct x)) 
=> 40320 
(nth factorial (count colours)) 
=> 40320 

नोट क्रमपरिवर्तन (कोषगत सूचकांक द्वारा) क्रम में उत्पन्न कर रहे हैं:

user=> (pprint (take 24 x)) 
(["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"] 
["red" "blue" "green" "yellow" "cyan" "magenta" "white" "black"] 
["red" "blue" "green" "yellow" "cyan" "black" "magenta" "white"] 
["red" "blue" "green" "yellow" "cyan" "black" "white" "magenta"] 
["red" "blue" "green" "yellow" "cyan" "white" "magenta" "black"] 
["red" "blue" "green" "yellow" "cyan" "white" "black" "magenta"] 
["red" "blue" "green" "yellow" "magenta" "cyan" "black" "white"] 
["red" "blue" "green" "yellow" "magenta" "cyan" "white" "black"] 
["red" "blue" "green" "yellow" "magenta" "black" "cyan" "white"] 
["red" "blue" "green" "yellow" "magenta" "black" "white" "cyan"] 
["red" "blue" "green" "yellow" "magenta" "white" "cyan" "black"] 
["red" "blue" "green" "yellow" "magenta" "white" "black" "cyan"] 
["red" "blue" "green" "yellow" "black" "cyan" "magenta" "white"] 
["red" "blue" "green" "yellow" "black" "cyan" "white" "magenta"] 
["red" "blue" "green" "yellow" "black" "magenta" "cyan" "white"] 
["red" "blue" "green" "yellow" "black" "magenta" "white" "cyan"] 
["red" "blue" "green" "yellow" "black" "white" "cyan" "magenta"] 
["red" "blue" "green" "yellow" "black" "white" "magenta" "cyan"] 
["red" "blue" "green" "yellow" "white" "cyan" "magenta" "black"] 
["red" "blue" "green" "yellow" "white" "cyan" "black" "magenta"] 
["red" "blue" "green" "yellow" "white" "magenta" "cyan" "black"] 
["red" "blue" "green" "yellow" "white" "magenta" "black" "cyan"] 
["red" "blue" "green" "yellow" "white" "black" "cyan" "magenta"] 
["red" "blue" "green" "yellow" "white" "black" "magenta" "cyan"]) 
+1

दोस्त, यह अब तक की सबसे प्यारी चीज है। यदि आप 1 एन तक फैक्टरियल में 1 बदलते हैं तो आप कर सकते हैं (एनएच-क्रमपरिवर्तन (रेंज 30) 100000000000000000000000); -> [0 1 2 3 4 5 9 26 2 9 13 10 18 28 16 15 8 27 20 25 23 1 9 14 21 22 24 7 12 17 6 ​​11] वास्तव में बहुत कम समय में। वास्तव में जो मैं चाहता था और खूबसूरती से किया। बहुत बहुत धन्यवाद। अगर आप इसके बारे में ब्लॉग करते हैं तो क्या आपको बुरा लगता है? (http://www.learningclojure.com/) –

+0

@ जॉन लोवरेंसस्पडन किसी भी तरह से उपयोग करने के लिए स्वतंत्र महसूस करें! –

1

मेरे सिफारिश: एक बंद का उपयोग करें और केवल क्रमपरिवर्तन की गणना एक बार। फिर उस पर एक तत्व का चयन करने के लिए उन क्रमपरिवर्तनों का दोबारा उपयोग करें। आपके फ़ंक्शन colour-shuffle में, क्रमिक गणना प्रत्येक कॉल के लिए फिर से गणना की जाती है जो बहुत ही कुशल नहीं है।

(use 'clojure.math.combinatorics) 

(def colours ["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"]) 

(def select-permutation 
    (let [perms (permutations colours)] 
    (fn [n] 
     (nth perms n)))) 

(defn colour-shuffle [n] 
    (let [cs (nth (permutations colours) n)] 
    [(first cs) (drop 1 cs)])) 

(time (do (def colour-shuffle-39038 (colour-shuffle 39038)) 
      (def colour-shuffle-28193 (colour-shuffle 28193)) 
      (def colour-shuffle-5667 (colour-shuffle 5667)) 
      (def colour-shuffle-8194 (colour-shuffle 8194)) 
      (def colour-shuffle-13895 (colour-shuffle 13895)) 
      (def colour-shuffle-2345 (colour-shuffle 2345)))) 

(time (do (def select-permutation-39038 (select-permutation 39038)) 
      (def select-permutation-28193 (select-permutation 28193)) 
      (def select-permutation-5667 (select-permutation 5667)) 
      (def select-permutation-8194 (select-permutation 8194)) 
      (def select-permutation-13895 (select-permutation 13895)) 
      (def select-permutation-2345 (select-permutation 2345)))) 

(time (do (def colour-shuffle-39038 (colour-shuffle 39038)) 
      (def colour-shuffle-28193 (colour-shuffle 28193)) 
      (def colour-shuffle-5667 (colour-shuffle 5667)) 
      (def colour-shuffle-8194 (colour-shuffle 8194)) 
      (def colour-shuffle-13895 (colour-shuffle 13895)) 
      (def colour-shuffle-2345 (colour-shuffle 2345)))) 

(time (do (def select-permutation-39038 (select-permutation 39038)) 
      (def select-permutation-28193 (select-permutation 28193)) 
      (def select-permutation-5667 (select-permutation 5667)) 
      (def select-permutation-8194 (select-permutation 8194)) 
      (def select-permutation-13895 (select-permutation 13895)) 
      (def select-permutation-2345 (select-permutation 2345)))) 

आउटपुट:

"Elapsed time: 129.023 msecs" 
"Elapsed time: 65.472 msecs" 
"Elapsed time: 182.226 msecs" 
"Elapsed time: 5.715 msecs" 

ध्यान दें कि यहां तक ​​कि तेजी से होता है का चयन-क्रमपरिवर्तन का उपयोग कर समय के दूसरे रन। ऐसा इसलिए है क्योंकि आलसी अनुक्रमों के परिणाम गणना के बाद कैश किए जाते हैं। आलसी-सीक में बहुत गहराई से तत्व का अनुरोध करने से सभी पिछले तत्वों की भी गणना की जाएगी। यही कारण है कि पहला रन ज्यादा लंबा लगता है। ताजा आलसी-सेक से 39039 वें तत्व का अनुरोध करते समय कम से कम 39040 तत्वों की गणना की जाएगी (32 के चक्स में)।

बीटीडब्ल्यू, यदि आपकी यादृच्छिक संख्याओं को किसी भी तरह से हार्डकोड किया जा रहा है, तो आप उपर्युक्त पुनर्प्राप्ति क्रमशः हार्डकोड भी कर सकते हैं।

+0

'हर बार मेरा प्रोग्राम चलाया जाता है ...' भाग के बारे में मत भूलना। – mobyte

+0

यदि आप प्रोग्राम चलाए जाने पर हर बार "यादृच्छिक" तत्व (क्रमपरिवर्तन) चुनते हैं, तो आप उन तत्वों को हार्ड-कोड भी कर सकते हैं। मेरे उत्तर में अंतिम पंक्ति देखें। –

4

clojure.core/shufflejava.util.Collection/shuffle का उपयोग करता है, जो एक वैकल्पिक यादृच्छिक संख्या जनरेटर लेता है। आप

(defn deterministic-shuffle 
    [^java.util.Collection coll seed] 
    (let [al (java.util.ArrayList. coll) 
     rng (java.util.Random. seed)] 
    (java.util.Collections/shuffle al rng) 
    (clojure.lang.RT/vector (.toArray al)))) 
संबंधित मुद्दे