2012-07-17 90 views
5

我使用的是docjure,它需要選擇列函數的列映射。我想抓住所有的列而不必手動指定它。 如何生成以下惰性無限矢量序列[:A:B:C:D:E ...:AA:AB:AC ....:ZZ ...:XFD]?Clojure理解示例

+1

向量不懶,但。 – Gert 2012-07-17 22:39:04

+0

它必須停在3還是可以永久繼續? – 2012-07-17 23:14:23

+0

@Gert它不一定是一個向量。 – KobbyPemson 2012-07-18 14:15:45

回答

6

你的問題可以歸結爲:「如何將數字轉換到基-26字母AZ的字符串?「。

這裏有一種方法可以做到這一點 - 可能不是最簡潔的方式,但使它更優雅是留給讀者的練習:)。

假設數字0-25映射到'A' - 'Z',26映射到'AA'等等。首先我們定義一個函數to-col,它將整數轉換爲列關鍵字。您可以使用該功能生成無限序列。

(defn to-col [num] 
    (loop [n num s()] 
    (if (> n 25) 
     (let [r (mod n 26)] 
     (recur (dec (/ (- n r) 26)) (cons (char (+ 65 r)) s))) 
     (keyword (apply str (cons (char (+ 65 n)) s)))))) 

這就給了你一個方法來生成列關鍵字的無限序列:

(take 100 (map to-col (range))) 
;; => (:A :B :C :D :E :F :G :H :I :J :K :L :M :N :O :P :Q :R :S :T :U :V :W 
;; :X :Y :Z :AA :AB :AC :AD :AE :AF :AG :AH :AI :AJ :AK :AL :AM :AN :AO :AP 
;; :AQ :AR :AS :AT :AU :AV :AW :AX :AY :AZ :BA :BB :BC :BD :BE :BF :BG :BH 
;; :BI :BJ :BK :BL :BM :BN :BO :BP :BQ :BR :BS :BT :BU :BV :BW :BX :BY :BZ 
;; :CA :CB :CC :CD :CE :CF :CG :CH :CI :CJ :CK :CL :CM :CN :CO :CP :CQ :CR 
;; :CS :CT :CU :CV) 
+0

這個解決方案不是懶惰的。 – 2014-05-28 01:02:31

0

有可能是一個辦法刪除了「」重複,但這裏的東西,對我的作品:

(def all-letters (map char (range 65 90))) 
(defn kw [& args] (keyword (apply str args))) 
(concat 
    (for [l all-letters] (kw l)) 
    (for [l all-letters l2 all-letters] (kw l l2)) 
    (for [l all-letters l2 all-letters l3 all-letters] (kw l l2 l3))) 
+0

(map char(範圍65 90))會產生字符\ A到\ Y,並且您的解決方案不是無限的。 – Gert 2012-07-17 23:26:19

2

這個答案是錯誤的;希望以教育的方式。

在數學上你要求的是一個字母的無限序列的所有子集的懶惰序列。

(take 40 (map #(keyword (apply str %)) 
      (rest (combinatorics/subsets "ABCDEFGHIJKLMNOPQRSTUVWXYZ")))) 
(:A :B :C :D :E :F :G :H :I :J :K :L :M :N 
:O :P :Q :R :S :T :U :V :W :X :Y :Z :AB :AC 
:AD :AE :AF :AG :AH :AI :AJ :AK :AL :AM :AN :AO) 

foo.core> (nth (map #(keyword (apply str %)) 
       (rest (combinatorics/subsets "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))) 
       40000) 
:BLOUZ 

project.clj:

(defproject foo "1.0.0-SNAPSHOT" 
    :description "FIXME: write description" 
    :dependencies [[org.clojure/clojure "1.3.0"] 
       [ org.clojure/math.combinatorics "0.0.3"]] 
    :dev-dependencies [[swank-clojure/swank-clojure "1.4.0"]]) ; swank) 

使用math.combanatorics:

(ns foo.core 
    (:require [clojure.math.combinatorics :as combinatorics])) 
+0

(休息...)是這些刪除我們不關心的空子集 – 2012-07-18 00:32:45

+0

聰明的讀者會注意到這個序列它實際上並不是無限的...... ;-)但太陽會先燒掉。 – 2012-07-18 00:35:06

+0

哎呀,這是錯誤的,它是ommiting:AA,讓我們看看這是否可以修復 – 2012-07-18 00:35:52

1

我想這可能是你要找的人(如果不是,那麼,在這種事情至少這是我認爲「正確」的答案應該是; o)。

(defn stream [seed] 
    (defn helper [slow] 
    (concat (map #(str (first slow) %) seed) (lazy-seq (helper (rest slow))))) 
    (declare delayed) 
    (let [slow (cons "" (lazy-seq delayed))] 
    (def delayed (helper slow)) 
    delayed)) 

(take 25 (stream ["a" "b" "c"])) 
("a" "b" "c" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc" "aaa" "aab" "aac" "aba" "abb" "abc" "aca" "acb" "acc" "baa" "bab" "bac" "bba") 

Code in git。我懷疑我濫用def可怕,但它的作品。

這個想法很簡單:我從序列中獲取輸出並將其反饋回來。對於輸出中的每個值(也是輸入),我通過在種子序列中追加每個字母來生成一個新的輸出。由於這是循環的,它只是繼續前進(在輸入中有一個初始「」,但不是輸出,這有助於避免從無到有創建任何東西)。

將輸出輸入到輸入中的過程在Haskell的一篇相當着名的論文中被稱爲「捆綁結」。但是在Clojure中做這件事很難,因爲它是一種熱切的語言(甚至懶惰的序列也不夠「懶惰」) - 我能找到的唯一解決方案是與def混淆(我懷疑有人可能會用delayforce做得更好,但是我沒有運氣)。

也許它甚至可以寫成地圖?

Tying the knot in Clojure: circular references without (explicit, ugly) mutation?一個答案(這是相同的思路jneira的答案)[2012-07-19更新與更緊湊的代碼]

相關問題有更好的代碼。

爲了完整起見,這裏使用的最終版本iterate

(defn stream [seed] 
    (defn helper [slow] (mapcat (fn [c] (map #(str c %) seed)) slow)) 
    (apply concat (iterate helper seed))) 
+0

在Clojure中,使用形式def和defn的形式被認爲是不好的風格,除了在頂層之外。在流內調用(defn helper ...)的問題在於它是副作用,重新定義了頂層var。你應該使用(let [helper(fn [slow] ...)] ...)來定義helper,或者使用letfn來代替。 – 2014-05-28 00:56:47

4

爲corecursion基本Clojure的函數(?和 「綁結」 也差不多了,沒有)是迭代:

(def abc (map (comp str char) (range 65 91))) 
(defn cols [seed] 
    (let [next #(for [x %] (for [y seed] (str x y)))] 
    (->> (iterate #(apply concat (next %)) seed) 
     (mapcat identity)))) 

(time (first (drop 475254 (cols abc)))) 
"Elapsed time: 356.879148 msecs" 
"AAAAA" 

(doc iterate) 
------------------------- 
clojure.core/iterate 
([f x]) 
    Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects 

編輯:函數的泛化以返回集合的「有序」子集

(defn ordered-combinations [seed] 
    (->> (map list seed) 
     (iterate #(for [x % y seed] (concat x [y]))) 
     (mapcat identity))) 

(def cols 
    (let [abc (map char (range 65 91))] 
    (map #(apply str %) (ordered-combinations abc)))) 

user> (take 30 (map #(apply str %) cols)) 
("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "AA" "AB" "AC" "AD") 
user> (take 28 (ordered-combinations [0 1])) 
((0) (1) (0 0) (0 1) (1 0) (1 1) (0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1) (0 0 0 0) (0 0 0 1) (0 0 1 0) (0 0 1 1) (0 1 0 0) (0 1 0 1) (0 1 1 0) (0 1 1 1) (1 0 0 0) (1 0 0 1) (1 0 1 0) (1 0 1 1) (1 1 0 0) (1 1 0 1)) 
-1
#include<stdio.h> 
int main() 
{ 
int n=703; 

char arr[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; 

while(n){ 
printf("%c ",arr[(n)%26]); 
n=(n)/26; 

} 
return 0; 
} 

傢伙就是這麼簡單,或者我錯過了一些東西...... 當然上面的程序打印所需的字符串反向 我們可以通過使用遞歸或者將它存儲在一個字符串中來反轉它。 ..

+0

你的解決方案不在clojure – KobbyPemson 2012-10-09 14:07:18

+0

@KobbyPemson你可以解釋你的意思..我沒有讓你.. – 2012-10-09 14:43:32

2

正如jneira迭代提到的感覺就像這樣做的正確方法。

這是他的功能的改進,應該更清楚地理解,因爲它涉及較少的中間類型。它不像有些根據各地循環/易復發的其他​​解決方案完全懶:

(defn column-names-seq [alphabet] 
    (->> (map str alphabet) 
    (iterate (fn [chars] 
       (for [x chars 
         y alphabet] 
        (str x y)))) 
    (apply concat))) 

要使用它,只需要提供一個字母列e.g:

(take 30 (column-names-seq "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) ;; => ("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "AA" "AB" "AC" "AD")