我正在使用docjure,它的select-columns函数需要一个列映射。我想抓住我的所有列而不必手动指定它。 如何生成以下作为惰性无限向量序列[:A:B:C:D:E ...:AA:AB:AC ....:ZZ ......:XFD]?
答案 0 :(得分:6)
您的问题归结为:" 如何将数字转换为字母A-Z的基数为26的字符串?"。
这是实现这一目标的一种方式 - 可能不是最简洁的方式,但让它更优雅留给读者练习:)。
假设数字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)
答案 1 :(得分: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))
答案 2 :(得分: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]))
答案 3 :(得分:2)
正如jneira所说,iterate感觉就像这样做的正确方法。
这是对他的功能的改进,应该更清楚地理解,因为它涉及较少的中间类型。与基于loop / recur的其他一些解决方案不同,它完全是懒惰的:
(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")
答案 4 :(得分: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
(我怀疑有人可能会做得更好{ {1}}和delay
,但我没有运气。
也许它甚至可以写成地图?
[2012-07-19更新更紧凑的代码]
在Tying the knot in Clojure: circular references without (explicit, ugly) mutation?的答案中有更好的代码的相关问题(这与jneira的答案相同)。
为了完整性,这是使用force
的最终版本:
iterate
答案 5 :(得分:0)
可能有一种方法可以删除“for”复制,但这里有一些对我有用的东西:
(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)))
答案 6 :(得分:-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;
}
伙计们就是这么简单,或者我错过了什么...... 当然上面的程序反向打印所需的字符串 我们可以通过使用递归或将其存储在字符串中来反转它...