Clojure 返回列表中的所有元素
我有一个函数Clojure 返回列表中的所有元素,clojure,Clojure,我有一个函数 (defn my-fn [a b & args] [a (for [arg args] (into [] (butlast arg))) b]) 如果我做了(我的fn[12][34][5 6 2][7 8 3]) 它返回[[12]([56][78])[34] 我希望输出为[[1 2][5 6][7 8][3 4]],但我不知道如何执行此操作 任何帮助都将不胜感激。这里有一个解决方案: (defn my-fn [a b & args] (
(defn my-fn [a b & args]
[a
(for [arg args]
(into [] (butlast arg)))
b])
如果我做了(我的fn[12][34][5 6 2][7 8 3])
它返回[[12]([56][78])[34]
我希望输出为[[1 2][5 6][7 8][3 4]]
,但我不知道如何执行此操作
任何帮助都将不胜感激。这里有一个解决方案:
(defn my-fn [a b & args]
(vec
(concat
[a]
(for [arg args]
(into [] (butlast arg)))
[b])))
(my-fn [1 2] [3 4] [5 6 2] [7 8 3])
=> [[1 2] [5 6] [7 8] [3 4]]
请注意,concat
返回一个惰性列表,用于处理更大和/或更复杂的问题。外部vec
将惰性列表转换为具体的向量。本例中不需要它,如果需要,可以将其删除
另一个注意事项是,concat
期望每个参数都是一个列表/向量,因此我将a
和b
包装成了一个元素向量。的输出已经是一个(惰性)列表
由于conj
、cons
、concat
等在行为上可能有些不直观,因此您可能希望签出助手函数glue
、append
、prepend
、&friends
背景
假设我们有一个标量和向量(或列表)的混合体,我们想把它们组合成一个向量。我们想要一个函数???给我们以下结果:
(??? 1 2 3 [4 5 6] 7 8 9) => [1 2 3 4 5 6 7 8 9]
Clojure没有这个功能。相反,我们需要将所有标量包装成向量,然后使用胶水或混凝土:
; can wrap individually or in groups
(glue [1 2 3] [4 5 6] [7 8 9]) => [1 2 3 4 5 6 7 8 9] ; could also use concat
(glue [1] [2] [3] [4 5 6] [7] [8] [9]) => [1 2 3 4 5 6 7 8 9] ; could also use concat
总是将标量值包装成向量,只是为了将它们与偶尔的向量值组合在一起,这可能会很不方便。相反,展开向量值,然后将结果与其他标量组合可能更方便。我们可以做到:
它还将递归地用于嵌套的unwrap
调用:
(->vector 1 (unwrap [2 3 (unwrap [4 5 6]) 7 8]) 9) => [1 2 3 4 5 6 7 8 9]
这里有一个解决方案:
(defn my-fn [a b & args]
(vec
(concat
[a]
(for [arg args]
(into [] (butlast arg)))
[b])))
(my-fn [1 2] [3 4] [5 6 2] [7 8 3])
=> [[1 2] [5 6] [7 8] [3 4]]
请注意,concat
返回一个惰性列表,用于处理更大和/或更复杂的问题。外部vec
将惰性列表转换为具体的向量。本例中不需要它,如果需要,可以将其删除
另一个注意事项是,concat
期望每个参数都是一个列表/向量,因此我将a
和b
包装成了一个元素向量。
的输出已经是一个(惰性)列表
由于conj
、cons
、concat
等在行为上可能有些不直观,因此您可能希望签出助手函数glue
、append
、prepend
、&friends
背景
假设我们有一个标量和向量(或列表)的混合体,我们想把它们组合成一个向量。我们想要一个函数???给我们以下结果:
(??? 1 2 3 [4 5 6] 7 8 9) => [1 2 3 4 5 6 7 8 9]
Clojure没有这个功能。相反,我们需要将所有标量包装成向量,然后使用胶水或混凝土:
; can wrap individually or in groups
(glue [1 2 3] [4 5 6] [7 8 9]) => [1 2 3 4 5 6 7 8 9] ; could also use concat
(glue [1] [2] [3] [4 5 6] [7] [8] [9]) => [1 2 3 4 5 6 7 8 9] ; could also use concat
总是将标量值包装成向量,只是为了将它们与偶尔的向量值组合在一起,这可能会很不方便。相反,展开向量值,然后将结果与其他标量组合可能更方便。我们可以做到:
它还将递归地用于嵌套的unwrap
调用:
(->vector 1 (unwrap [2 3 (unwrap [4 5 6]) 7 8]) 9) => [1 2 3 4 5 6 7 8 9]
您的for
语句返回一个列表
(defn my-fn [a b & args]
(->> [[a]
(map (comp vec butlast) args)
[b]]
(apply concat)
vec))
最后的vec
将您的seq转换为一个向量。您的for
语句返回一个列表
(defn my-fn [a b & args]
(->> [[a]
(map (comp vec butlast) args)
[b]]
(apply concat)
vec))
最后一个vec
将您的seq转换为一个向量。我将转换为所有映射值,然后在末尾执行conj
b
。例如
(defn my-fn [a b & args]
(-> [a]
(into (map (comp vec butlast) args))
(conj b)))
我将转换为[a]
所有映射的值,然后在最后执行conj
b
。例如
(defn my-fn [a b & args]
(-> [a]
(into (map (comp vec butlast) args))
(conj b)))
还有一个变体,使用引号和非引号拼接:
user> (defn my-fn2 [a b & args]
`[~a ~@(map (comp vec butlast) args) ~b])
;;=> #'user/my-fn2
user> (my-fn2 [1 2] [3 4] [5 6 2] [7 8 3])
;;=> [[1 2] [5 6] [7 8] [3 4]]
还有一个变体,使用引号和非引号拼接:
user> (defn my-fn2 [a b & args]
`[~a ~@(map (comp vec butlast) args) ~b])
;;=> #'user/my-fn2
user> (my-fn2 [1 2] [3 4] [5 6 2] [7 8 3])
;;=> [[1 2] [5 6] [7 8] [3 4]]
使用Python风格的生成器函数的替代解决方案
您也可以通过以下方式解决此问题:
(ns tst.clj.core
(:use clj.core tupelo.test)
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(defn my-fn [a b & args]
(lazy-gen
(yield a)
(yield-all (for [arg args]
(into [] (butlast arg))))
(yield b)))
(my-fn [1 2] [3 4] [5 6 2] [7 8 3]) => ([1 2] [5 6] [7 8] [3 4])
这里,lazy gen
为“生成器函数”创建了一个上下文,其中使用yield
和yield all
函数将连续值添加到输出列表中。请注意,yield all
函数类似于Clojure“unquote spicing”操作符~@
并将其序列“展开”到输出流中
更简单的答案是深入了解原始解决方案的部分,以应用产量
输出抽头:
(defn my-fn2 [a b & args]
(lazy-gen
(yield a)
(doseq [arg args]
(yield (butlast arg)))
(yield b)))
(my-fn2 [1 2] [3 4] [5 6 2] [7 8 3]) => ([1 2] (5 6) (7 8) [3 4])
此版本的解决方案更接近您的原始逻辑,
并且避免了for
函数意外地将其结果包装到序列中,这与未包装在向量中的a
和b
值冲突。我们也不再需要原始函数的(into[…)
部分
请注意,我们已将
的替换为doseq
,因为:
- 我们不再使用循环的返回值
- 因此,懒惰的解决方案永远不会运行
使用Python风格生成器函数的替代解决方案
您也可以通过以下方式解决此问题:
(ns tst.clj.core
(:use clj.core tupelo.test)
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(defn my-fn [a b & args]
(lazy-gen
(yield a)
(yield-all (for [arg args]
(into [] (butlast arg))))
(yield b)))
(my-fn [1 2] [3 4] [5 6 2] [7 8 3]) => ([1 2] [5 6] [7 8] [3 4])
这里,lazy gen
为“生成器函数”创建了一个上下文,其中使用yield
和yield all
函数将连续值添加到输出列表中。请注意,yield all
函数类似于Clojure“unquote spicing”操作符~@
并将其序列“展开”到输出流中
更简单的答案是深入了解原始解决方案的部分,以应用产量
输出抽头:
(defn my-fn2 [a b & args]
(lazy-gen
(yield a)
(doseq [arg args]
(yield (butlast arg)))
(yield b)))
(my-fn2 [1 2] [3 4] [5 6 2] [7 8 3]) => ([1 2] (5 6) (7 8) [3 4])
此版本的解决方案更接近您的原始逻辑,
并且避免了for
函数意外地将其结果包装到序列中,这与未包装在向量中的a
和b
值冲突。我们也不再需要原始函数的(into[…)
部分
请注意,我们已替换