Warm tip: This article is reproduced from serverfault.com, please click

其他-在Clojure中使用conj和doseq在列表中添加元素

(其他 - Adding element in the list using conj and doseq in clojure)

发布于 2020-12-02 17:06:56

在下面的代码中,我想使用(conj listvalue countString)在列表中添加一个元素

(defn unique-character [parms]
  (let [split (#(str/split % #"") parms)
        countString (count split)
        listvalue #{}]
  (dbg (doseq [countString split]
               (println countString)
               (conj listvalue countString)
               (println listvalue)
         ))listvalue))

(unique-character "Leeeeeerrroyyy")

Output to be - Leroy

但是我得到一个空列表作为输出结果

有人可以帮我为什么不将字符添加到列表中吗,也许这不是很好的代码,但是我想了解conj在doseq中的表现

Questioner
Ganesh
Viewed
0
Rulle 2020-12-03 04:24:03

最重要的是,conj将不会更改输入序列,而是将返回输入序列的新版本,并在最后添加元素:

(def x [:a :b :c])

(conj x :d)
x
;; => [:a :b :c]

(def y (conj x :d))
y
;; => [:a :b :c :d]

这是为什么要在命令式语言及其标准库上使用Clojure及其标准库的许多重要原因之一:让函数返回集合的新版本而不是对其进行修改,会使通过程序的数据流更易于推理,并使得并发也更容易。

你也不需要使用来分割字符串split,因为可以直接将其视为序列。确实doseq会像其他语言中的for-each-loop一样逐个元素地循环序列,以便在每次迭代中都产生一些副作用但是conj除了返回输入序列的新版本之外,没有副作用。

在这种情况下,我们将使用reduce,就像doseq遍历一个序列一样。但是它将loop-state在下面的代码中跟踪一个值(),该保存循环的状态并在最后返回。这是unique-characters所问问题的功能重写版本

(defn unique-characters [parms]
  (reduce (fn [loop-state input-character]
            (conj loop-state input-character)) ;; <-- Return next loop state

          #{} ;; <-- Initial loop state (that is "listvalue")

          parms ;; <-- The input string (sequence of characters)
          ))

(unique-characters "Leeeeeerrroyyy")
;; => #{\e \L \o \r \y}

这将返回一组输入序列的字符。从问题的措辞来看,这可能不是你想要的结果。这是一个修改后的版本,它最多将每个字符添加到输出序列一次并生成一个字符串。

(defn unique-characters-2 [parms]
  (apply str ;; <-- Build a string from the value returned by reduce below
         (reduce (fn [loop-state input-character]
                   (if (some #(= input-character %) loop-state)
                     loop-state
                     (conj loop-state input-character)))

                 [] ;; <-- Initial loop state

                 parms ;; <-- Input string (sequence of characters)
                 )))

(unique-characters-2 "Leeeeeerrroyyy")
;; => "Leroy"