clojure - 有序的2个列表的成对组合

Bri*_*ian 4 combinations list clojure

作为clojure的新手,我仍在努力完成其功能.如果我有2个列表,说"1234"和"abcd"我需要制作长度为4的所有可能的有序列表.我想要的长度为4的输出是:

("1234" "123d" "12c4" "12cd" "1b34" "1b3d" "1bc4" "1bcd" 
 "a234" "a23d" "a2c4" "a2cd" "ab34" "ab3d" "abc4" "abcd")
Run Code Online (Sandbox Code Playgroud)

其中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))))
Run Code Online (Sandbox Code Playgroud)

输出将是上面16个有序列表中的1个.两个输入列表中的每一个将始终具有相等的长度,例如2,3,4,5,最多说2 ^ 38或在可用的ram内.在上面的函数中,我试图修改它以生成所有有序列表但失败了.希望有人可以帮助我.谢谢.

ama*_*loy 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")
Run Code Online (Sandbox Code Playgroud)

这种递归嵌套for是一种非常有用的模式,用于通过选择的"树"创建一系列路径.无论是实际的树,还是反复重复的相同选择,或者(如此处)一组不依赖于先前选择的N个选项,这是一个可用的便利工具.


Raf*_*ird 6

您还可以充分利用cartesian-productclojure.math.combinatorics包,尽管这需要你的一些数据预处理和后转化:

(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")
>
Run Code Online (Sandbox Code Playgroud)