Clojure初学者 - 实施扁平化,麻烦与“让”#39;

时间:2018-04-14 13:50:12

标签: clojure functional-programming

Clojure的新手。

Input - ["a" ["b" "c"] "d"]
Expected output - ["a" "b" "c" "d"]

我尝试做的事情 - 创建一个空的向量('结果'),然后在输入集合上做两个剂量以填充结果'起来,最后回复填满的结果'。但是该函数返回一个空向量。我做错了什么?

(flat ["a" ["b" "c"] "d"]) 

(defn flat [arr]
(let [result []]
     (doseq [element arr] 
            (if (coll? element) (doseq [element2 element] (conj result element2)) 
                (conj result element))) result))

3 个答案:

答案 0 :(得分:1)

正如其他人所指出的,你不能改变结果。如果你确实想要用变异来实现你的函数,你需要一个原子,你可以用swap来变异!

(defn flat [arr]
  (let [result (atom [])]
     (doseq [element arr] 
            (if (coll? element) (doseq [element2 element] (swap! result conj element2)) 
                (swap! result conj element)))
     @result))

但请注意,这只会给您一个单一的展平程度,您只需使用

即可完成
(apply concat <your seq>)

一个简单的,递归的,多层次的扁平化是:

(defn flat [x] (if (coll? x) (mapcat flat x) [x]))

答案 1 :(得分:0)

#!/usr/bin/env boot

(def inp ["a" "b" ["c" "d" "e" ["f" "g" "h"] "i"] "j" "k"])

(defn flat 
  ([xs] (flat xs []))
  ([xs acc]
    (if (empty? xs) acc
      (if (vector? (first xs))
        (flat (rest xs) (flat (first xs) acc))
        (recur (rest xs) (conj acc (first xs)))))))

(println (flat inp))  ;[a b c d e f g h i j k]

基本思想是检查第一个元素是否是一个列表,如果这样,则递归该列表(flat (first xs) acc)将每个元素添加到累加器,然后继续给出(flat (rest xs) (flat (first xs) acc))列表的其余部分。否则只会重复个别因素。

我们也可以使用其他结构,例如letcond

答案 2 :(得分:0)

如果你想要一个快速版本的flatten,请参阅clojure.core.reducers / flatten。

(require '[clojure.core.reducers :as r])
(defn rflatten [coll] (into [] (r/flatten coll)))