返回列表中的所有元素

时间:2017-06-14 13:41:01

标签: clojure

我有一个功能

(defn my-fn [a b & args]
  [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]]

我希望输出为[[1 2] [5 6] [7 8] [3 4]],但我无法弄清楚如何执行此操作

非常感谢任何帮助。

5 个答案:

答案 0 :(得分:5)

into [a]所有的映射值,最后是conj b。 E.g。

(defn my-fn [a b & args]
  (-> [a]
      (into (map (comp vec butlast) args))
      (conj b)))

答案 1 :(得分:1)

以及另一个变体,使用引用和非引用拼接:

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]]

答案 2 :(得分:0)

这是一个解决方案:

(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会返回一个惰性列表,该列表适用于较大和/或更复杂的问题can cause a StackOverflowException。外部vec将惰性列表转换为具体向量。这个例子没有必要,你可以根据需要删除它。

另外注意,concat期望每个参数都是一个列表/向量,所以我将ab包装成1个元素的向量。 for的输出已经是(懒惰)列表。

由于conjconsconcat等行为可能有点不直观,您可能希望查看辅助函数glue,{{1 },append,&朋友in the Tupelo library

背景

假设我们有混合的标量&我们想要组合成单个向量的向量(或列表)。我们想要一个功能???给我们以下结果:

prepend

Clojure没有这方面的功能。相反,我们需要将所有标量包装到矢量中,然后使用胶水或连接:

(???  1 2 3 [4 5 6] 7 8 9)  =>  [1 2 3 4 5 6 7 8 9]

总是将标量值包装到矢量中只是为了将它们与偶然的矢量值组合起来可能不方便。相反,打开矢量值可能更方便,然后将结果与其他标量组合。我们可以做到with the ->vector and unwrap functions

; 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

对于嵌套的(->vector 1 2 3 4 5 6 7 8 9) => [1 2 3 4 5 6 7 8 9] (->vector 1 (unwrap [2 3 4 5 6 7 8]) 9) => [1 2 3 4 5 6 7 8 9] 调用,它也会递归工作:

unwrap

答案 3 :(得分:0)

您的for语句会返回一个列表。

(defn my-fn [a b & args]
    (->> [[a]
         (map (comp vec butlast) args)
         [b]]
      (apply concat)
      vec))

最终vec将您的seq转换为矢量。

答案 4 :(得分:0)

使用Python样式生成器函数的备用解决方案

你也可以这样解决:

null

此处(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-genyield函数将连续值添加到输出列表中。请注意,yield-all函数类似于Clojure" unquote-splicing" operator yield-all和" unwraps"它的序列进入输出流。

更简单的答案是深入了解原始解决方案的~@部分,以应用for输出点按:

yield

此版本的解决方案更贴近原始逻辑, 并避免(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]) 函数将其结果包装成序列的意外复杂性,该序列与未包含在向量中的fora值冲突。我们也不再需要原始函数的b部分。

请注意,我们已将(into [] ...)替换为for,因为:

  • 我们不再使用循环的返回值
  • 因此,懒惰的解决方案永远不会运行