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[…)
部分

请注意,我们已替换