Clojure来理解例如(Clojure For Comprehension example)

2019-06-26 09:07发布

我使用docjure ,它需要为它选择-列功能的列映射。 我想抓住我的所有列,而不必手动指定。 如何生成以下作为一个懒惰的无限向量序列[:A:B:C:d:电子...:AA:AB:AC ....:ZZ ...:XFD]?

Answer 1:

你的问题可以归结为:“ 我如何将数字转换成基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)


Answer 2:

对于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))


Answer 3:

这个答案是错误的; 希望在教育方式。

数学上你所要求的是字母表中的无限序列的所有子集的懒惰序列 。

(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]))


Answer 4:

正如jneira迭代提到感觉就像做的正确方法。

下面是对他的功能的改善,应该是更清楚的理解,因为它涉及较少的中间类型。 它不像有些根据各地循环/易复发的其他​​解决方案完全懒:

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

要使用它,只需要提供一个字母列如:

(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")


Answer 5:

我想这可能是你要找的那种东西(如果不是,好吧,至少它是什么,我认为“正确”的答案应该是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")

代码的git 。 我怀疑我虐待def可怕,但它的作品。

这个想法是很简单的:我从序列输出并反馈自身。 对于在输出每个值(其也是输入),我生成通过附加各字母的种子序列的新的输出。 由于这是圆形的,它只是不断去(有一个初始的“”,这是在输入,而不是输出,有助于避免产生无中生有)。

供给输出到输入的过程被称为在Haskell的一个相当著名的论文“绑结”。 但它很难用Clojure做的,因为它是一个渴望语言(甚至懒惰序列不是“懒足够”) -我能找到的唯一解决办法是用那些乱七八糟的def (我怀疑有人可能会做的更好delayforce ,但我没有运气)。

也许它甚至可以被写成地图吗?

[更新2012-07-19与更紧凑的代码]

在回答相关问题有更好的代码没有(显式的,丑陋的)突变循环引用:绑结Clojure中? (这是相同的思路jneira的答案)。

为了完整起见,这里使用的最终版本iterate

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


Answer 6:

有可能是一个办法删除了“”重复,但这里的东西,对我的作品:

(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)))


Answer 7:

#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;
}

人是如此简单,因为这还是我失去了一些东西....当然上面的程序打印所需的atring相反,我们能够避免使用递归或将其存储在一个字符串扭转这种局面?



文章来源: Clojure For Comprehension example