我试图理解 Clojure 中这个笛卡尔积函数的语法
I'm trying to understand the syntax of this cartesian-product function in Clojure
这是笛卡尔积的一些代码,它可以是两个列表、两个向量或两者的任意数量的组合。我非常感谢对第二行、第四行和最后一行的帮助,解释每行在做什么
(defn cartesian-product ;function name definition
([] '(())) ;need help understanding this
([xs & more] ; at least two variables, xs is one of them
(mapcat #(map (partial cons %) ;mapcat means a create a concatenated map of the following
;still trying to figure out partial, but cons takes a
;variable and puts it in front of a sequence
(apply cartesian-product more)) ; this is the sequence that is mapped
; using (partial cons %)
xs))) ;not sure what this is here for
这是一个重新设计的版本,说明了正在发生的事情(以及如何发生):
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
;----------------------------------------------------------------------------
; Lesson: how map & mapcat work
(defn dup [x]
"Return 2 of the arg in a vector"
[x x])
(dotest
(let [nums [0 1 2]]
(is= (mapv inc nums) [1 2 3])
(is= (mapv dup nums) [[0 0] ; like a matrix, 2-D
[1 1]
[2 2]])
; mapcat glues together the inner "row" vectors. So the result is 1-D instead of 2-D
(is= (mapcat dup nums) [0 0 1 1 2 2])))
然后是修改后的代码
;----------------------------------------------------------------------------
(def empty-matrix [[]]) ; 0 rows, 0 cols
(defn cartesian-product ;function name definition
"When called with 1 or more sequences, returns a list of all possible combinations
of one item from each collection"
([] ; if called with no args
empty-matrix) ; return an empty matrix
; if called with 1 or more args,
([xs ; first arg is named `xs` (i.e. plural for x values)
& more] ; all other args are wrapped in a list named `more`
(let [recursion-result (apply cartesian-product more) ; get cartesian prod of sequences 2..N
inner-fn (fn [arg] (map ; for each recursion-result
(partial cons arg) ; glue arg to the front of it
recursion-result))
; for each item in the first sequence (xs), glue to front of
; each recursion result and then convert 2D->1D
output (mapcat inner-fn xs)]
output)))
和一些单元测试来展示它的实际效果
(dotest
(is= (cartesian-product [1 2 3]) [[1] [2] [3]])
(is= (cartesian-product [1 2 3] [:a :b])
[[1 :a]
[1 :b]
[2 :a]
[2 :b]
[3 :a]
[3 :b]])
(is= (cartesian-product [1 2 3] [:a :b] ["apple" "pea"])
[[1 :a "apple"]
[1 :a "pea"]
[1 :b "apple"]
[1 :b "pea"]
[2 :a "apple"]
[2 :a "pea"]
[2 :b "apple"]
[2 :b "pea"]
[3 :a "apple"]
[3 :a "pea"]
[3 :b "apple"]
[3 :b "pea"]]))
这是笛卡尔积的一些代码,它可以是两个列表、两个向量或两者的任意数量的组合。我非常感谢对第二行、第四行和最后一行的帮助,解释每行在做什么
(defn cartesian-product ;function name definition
([] '(())) ;need help understanding this
([xs & more] ; at least two variables, xs is one of them
(mapcat #(map (partial cons %) ;mapcat means a create a concatenated map of the following
;still trying to figure out partial, but cons takes a
;variable and puts it in front of a sequence
(apply cartesian-product more)) ; this is the sequence that is mapped
; using (partial cons %)
xs))) ;not sure what this is here for
这是一个重新设计的版本,说明了正在发生的事情(以及如何发生):
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
;----------------------------------------------------------------------------
; Lesson: how map & mapcat work
(defn dup [x]
"Return 2 of the arg in a vector"
[x x])
(dotest
(let [nums [0 1 2]]
(is= (mapv inc nums) [1 2 3])
(is= (mapv dup nums) [[0 0] ; like a matrix, 2-D
[1 1]
[2 2]])
; mapcat glues together the inner "row" vectors. So the result is 1-D instead of 2-D
(is= (mapcat dup nums) [0 0 1 1 2 2])))
然后是修改后的代码
;----------------------------------------------------------------------------
(def empty-matrix [[]]) ; 0 rows, 0 cols
(defn cartesian-product ;function name definition
"When called with 1 or more sequences, returns a list of all possible combinations
of one item from each collection"
([] ; if called with no args
empty-matrix) ; return an empty matrix
; if called with 1 or more args,
([xs ; first arg is named `xs` (i.e. plural for x values)
& more] ; all other args are wrapped in a list named `more`
(let [recursion-result (apply cartesian-product more) ; get cartesian prod of sequences 2..N
inner-fn (fn [arg] (map ; for each recursion-result
(partial cons arg) ; glue arg to the front of it
recursion-result))
; for each item in the first sequence (xs), glue to front of
; each recursion result and then convert 2D->1D
output (mapcat inner-fn xs)]
output)))
和一些单元测试来展示它的实际效果
(dotest
(is= (cartesian-product [1 2 3]) [[1] [2] [3]])
(is= (cartesian-product [1 2 3] [:a :b])
[[1 :a]
[1 :b]
[2 :a]
[2 :b]
[3 :a]
[3 :b]])
(is= (cartesian-product [1 2 3] [:a :b] ["apple" "pea"])
[[1 :a "apple"]
[1 :a "pea"]
[1 :b "apple"]
[1 :b "pea"]
[2 :a "apple"]
[2 :a "pea"]
[2 :b "apple"]
[2 :b "pea"]
[3 :a "apple"]
[3 :a "pea"]
[3 :b "apple"]
[3 :b "pea"]]))