对于clojure来说还是一个新手,我仍然在努力解决它的问题。如果我有2个列表,说“1234”和“abcd”我需要制作长度为4的所有可能的有序列表。我想要的长度为4的输出是:
("1234" "123d" "12c4" "12cd" "1b34" "1b3d" "1bc4" "1bcd"
"a234" "a23d" "a2c4" "a2cd" "ab34" "ab3d" "abc4" "abcd")
其中2 ^ n的数量取决于输入。
我编写了以下函数来通过随机遍历生成单个字符串/列表。 参数[par]就像[“1234”“abcd”]
(defn make-string [par] (let [c1 (first par) c2 (second par)] ;version 3 0.63 msec
(apply str (for [loc (partition 2 (interleave c1 c2))
:let [ch (if (< (rand) 0.5) (first loc) (second loc))]]
ch))))
输出将是上面16个有序列表中的1个。两个输入列表中的每一个将始终具有相等的长度,例如2,3,4,5,最多说2 ^ 38或在可用的ram内。在上面的函数中,我试图修改它以生成所有有序列表但失败了。希望有人可以帮助我。感谢。
答案 0 :(得分:7)
Mikera是正确的,你需要使用递归,但你可以做到这一点,同时更简洁,更一般 - 为什么使用两个字符串,当你可以使用N序列?
(defn choices [colls]
(if (every? seq colls)
(for [item (map first colls)
sub-choice (choices (map rest colls))]
(cons item sub-choice))
'(())))
(defn choose-strings [& strings]
(for [chars (choices strings)]
(apply str chars)))
user> (choose-strings "123" "abc")
("123" "12c" "1b3" "1bc" "a23" "a2c" "ab3" "abc")
这种递归嵌套for是一种非常有用的模式,用于通过选择的“树”创建一系列路径。无论是实际的树,还是反复重复的相同选择,或者(如此处)一组不依赖于先前选择的N个选项,这是一个可用的便利工具。
答案 1 :(得分:6)
您还可以利用clojure.math.combinatorics包中的cartesian-product
,但这需要对数据进行转换前后的转换:
(ns your-namespace (:require clojure.math.combinatorics))
(defn str-combinations [s1 s2]
(->>
(map vector s1 s2) ; regroup into pairs of characters, indexwise
(apply clojure.math.combinatorics/cartesian-product) ; generate combinations
(map (partial apply str)))) ; glue seqs-of-chars back into strings
> (str-combinations "abc" "123")
("abc" "ab3" "a2c" "a23" "1bc" "1b3" "12c" "123")
>
答案 2 :(得分:4)
诀窍是使函数递归,在每一步调用自己的列表的其余部分。
您可以执行以下操作:
(defn make-all-strings [string1 string2]
(if (empty? string1)
[""]
(let [char1 (first string1)
char2 (first string2)
following-strings (make-all-strings (next string1) (next string2))]
(concat
(map #(str char1 %) following-strings)
(map #(str char2 %) following-strings)))))
(make-all-strings "abc" "123")
=> ("abc" "ab3" "a2c" "a23" "1bc" "1b3" "12c" "123")
答案 3 :(得分:2)
(defn combine-strings [a b]
(if (seq a)
(for [xs (combine-strings (rest a) (rest b))
x [(first a) (first b)]]
(str x xs))
[""]))
现在我写了它,我意识到它是一个不那么通用的版本。
答案 4 :(得分:1)
您还可以使用0到16之间数字的二进制数字来形成组合:
如果一个位为零,则从第一个字符串中选择,否则从第二个字符
E.g。 6 = 2r0110 =&gt; “1bc4”,13 = 2r1101 =&gt; “ab3d”等。
(map (fn [n] (apply str (map #(%1 %2)
(map vector "1234" "abcd")
(map #(if (bit-test n %) 1 0) [3 2 1 0])))); binary digits
(range 0 16))
=> ("1234" "123d" "12c4" "12cd" "1b34" "1b3d" "1bc4" "1bcd" "a234" "a23d" "a2c4" "a2cd" "ab34" "ab3d" "abc4" "abcd")
同样的方法可以应用于从两个以上的字符串生成组合 假设您有3个字符串(“1234”“abcd”“ABCD”),将有81个组合(3 ^ 4)。使用base-3三进制数字:
(defn ternary-digits [n] (reverse (map #(mod % 3) (take 4 (iterate #(quot % 3) n))))
(map (fn [n] (apply str (map #(%1 %2)
(map vector "1234" "abcd" "ABCD")
(ternary-digits n)
(range 0 81))
答案 5 :(得分:0)
(def c1 "1234")
(def c2 "abcd")
(defn make-string [c1 c2]
(map #(apply str %)
(apply map vector
(map (fn [col rep]
(take (math/expt 2 (count c1))
(cycle (apply concat
(map #(repeat rep %) col)))))
(map vector c1 c2)
(iterate #(* 2 %) 1)))))
(make-string c1 c2)
=> ("1234" "a234" "1b34" "ab34" "12c4" "a2c4" "1bc4" "abc4" "123d" "a23d" "1b3d" "ab3d" "12cd" "a2cd" "1bcd" "abcd")