Clojure列表理解-在特定情况下只运行一次内部循环?

Clojure列表理解-在特定情况下只运行一次内部循环?,clojure,Clojure,有没有一种方法可以使用单一列表comp来实现以下目标,或者我需要其他方法 (def args'([:db/foo 12][:db/bar 34]{:a1:b2})) (定义myfunc[] “如果arg是映射,则只希望运行一次内部循环。” (对于[arg args[cmd¶ms]arg];“cmd¶ms”在映射时没有意义。 (如果(映射参数) arg (输入[cmd]参数))) 以上代码生成 => [[:db/foo 1 2] [:db/bar 3 4] {:a 1, :

有没有一种方法可以使用单一列表comp来实现以下目标,或者我需要其他方法

(def args'([:db/foo 12][:db/bar 34]{:a1:b2}))
(定义myfunc[]
“如果arg是映射,则只希望运行一次内部循环。”
(对于[arg args[cmd¶ms]arg];“cmd¶ms”在映射时没有意义。
(如果(映射参数)
arg
(输入[cmd]参数)))
以上代码生成

=> [[:db/foo 1 2] [:db/bar 3 4] {:a 1, :b 2} {:a 1, :b 2}]
但我真的想要

=>[[:db/foo 12][:db/bar 34]{:a1,:b2}]
显然,这不是完整的函数,如果arg是向量形式,但希望让map形式直接通过(而不被复制),我将进行变换


更新:我发现a有其根源,而“有条件地执行内部循环”实际上是一个必须的概念,因此这并不奇怪一个单一的列表理解不容易表达,这完全是fp构造。

这就是你想要做的吗?: 从现有序列构建新序列。对于输入序列中的每个元素,有两种可能的情况:

  • 这是一个映射:在这种情况下,只需将其附加到结果序列
  • 否则它是一个序列,它的元素可能应该被转换并附加到结果序列中
如果这是您想要做的,那么可以通过首先将输入序列的元素映射到子序列,然后将这些序列连接起来以形成结果序列来方便地表示此计算

正如@cfrick所建议的,有一种
mapcat
将映射与连接相结合,可以通过直接将序列传递给
mapcat

(mapcat (fn [x] (if (map? x) [x] x)) args)
或者使用
mapcat
作为传感器

(into [] (mapcat (fn [x] (if (map? x) [x] x))) args)

我认为
for
不适合表示此计算。

在我提出解决方案之前,我对您提供的函数
myfunc
有几点意见:

  • 文档字符串放错了位置。我知道这很奇怪,但是doc字符串必须在函数的参数之前,所以在
    []
    之前
  • 我认为,您对指令使用的
    不是您所期望的。您应该看看中的示例。主要是
    for
    指令很适合从列表构造笛卡尔积
我希望我正确地理解了你想要实现的目标。在我的命题中,我使用递归通过
循环
指令构建一个向量,该向量将包含每个参数:

(defn myfunc“如果arg是映射,则只希望运行一次内部循环。”
[&args]
(循环[arg以解析args
res[]]
(如果(空?要分析的参数)
物件
(let[arg(要分析的第一个arg)
要分析的新参数(要分析的rest参数)]
(如果(映射参数)
(重现要分析的新参数(conj res arg))
(重现要分析的新参数(转换为res参数))
)))))
(myfunc[:db/foo 12][:db/bar 34]{:a1:b2})
;; => [[:db/foo 12][:db/bar 34]{:a1,:b2}]
(myfunc{:a1:b2}[:db/foo2][:db/bar 34]]
;; => [{:a1,:b2}[:db/foo 12][:db/bar 34]]

(mapcat(fn[x](if(map?x)[x]x)))
因为传感器似乎也这样做(至少对于给定的测试用例)@cfrick我完全忘记了
mapcat
。这是一个很大的改进,东西变得简洁多了!