【问题标题】:Clojure changing binding local's value depending on conditionsClojure 根据条件更改绑定本地的值
【发布时间】:2014-11-24 06:50:37
【问题描述】:

根据以下条件更改本地的惯用方法是什么?在这里,我根据某些条件更改 x 的值。

(defn person-story
 [person]
  (let [x (str "My name is " (:firstname person) " " (:lastname person) "." )
    x (if (:showaddress person) (str x " I live in " (:address person) ".") x)
    x (if (:showage person) (str x " I am " (:age person) " yrs old. ") x)
    x (if (seq (:hobby person)) (str x " I like " (clojure.string/join ", " (:hobby person)) ".") x)]
x))

(person-story {:firstname "John" :lastname "Doe" :age 45 :showage false :address "67 Circe Ave" :showaddress true :hobby ["movie" "music" "money"]})

那会输出:

"My name is John Doe. I live in 67 Circe Ave. I like movie, music, money."

如果我用 java 来做,我会做这样的事情:

    StringBuilder sb = new StringBuilder("My name is ");
    sb.append(person.get("firstname")).append(" ");
    sb.append(person.get("lastname")).append(" ");
    if (showaddress) sb.append("I live in ").append(person.get("address")).append(" ");
    if (showage) sb.append("I am ").append(person.get("age")).append(" yrs old. ");
    List<String> hobbies = person.get("hobby");
    if ( hobbies != null && !hobbies.isEmpty()) sb.append("I like "). append(StringUtils.join(hobbies, ", "));
    return sb.toString()

实现我在 clojure 中实现的相同目标的最佳方法是什么?对不起标题,我想不出更好的标题。


解决方案

谢谢 xsc 和 amalloy,两个答案都很棒。我接受了 amalloy 的回答,因为它展示了一种全新的解决问题的方法,但两者都赞成。 以下是两种建议的解决方案的 sn-ps:

合金的方法:

(defn person-story2 [person]
  (let [tests [[:showaddress #(format " I live in %s." (:address %))]
               [:showage #(format " I am %s yrs old." (:age %))]
               [(comp seq :hobbies) #(format " I like %s." (clojure.string/join ", " (:hobbies %)))]]]
    (apply str (format "My name is %s %s." (:firstname person) (:lastname person))
           (for [[test f] tests
                 :when (test person)]
             (f person)))))


(person-story2 {:firstname "John" :lastname "Doe" :showage true :age 50  :showaddress true :address "Universal Studios" :hobbies ["movies" "music" "money"]})

输出:

"My name is John Doe. I live in Universal Studios. I am 50 yrs old. I like movies, music, money."

xsc的方法:

(defn person-story 
  [{:keys [firstname lastname address showaddress age showage hobbies] :as person}]
  (cond-> 
   (str "My name is " firstname " " lastname ". ")
   showaddress (str "I live in " address ". ")
   showage (str "I am " age " yrs old. ")
   (seq hobbies) (str "I like " (clojure.string/join ", " hobbies))))

(person-story {:firstname "John" :lastname "Doe" :showage false :age 50 :address "Universal Studios" :showaddress true :hobbies ["movies" "music" "money"]})

输出:

"My name is John Doe. I live in Universal Studios. I like movies, music, money"

【问题讨论】:

    标签: clojure let


    【解决方案1】:

    从 Clojure 1.5 开始,cond-&gt;/cond-&gt;&gt; 的工作方式与 -&gt;/-&gt;&gt; 类似,但条件决定是否执行单个步骤:

    (cond->
      (str "My name is " (:firstname p) " " (:lastname p) ".")
      (:showaddress p) (str "I live in " (:address p) ".")
      (:showage p)     (str "I am " (:age p) " yrs old.")
      ...)
    

    这将是条件字符串构建的惯用解决方案。或者,您可以使用以下内容:

    (clojure.string/join
      [(str "My name is " (:firstname p) " " (:lastname p) ".")
       (if (:showaddress p)
         (str "I live in " (:address p) "."))
       ...])
    

    这利用了nil 在连接字符串时将被忽略的事实。

    【讨论】:

      【解决方案2】:

      为避免重复任何无用的内容(例如,if 条件或您正在遍历所有内容的 x),请定义您要运行的测试的列表,以及在测试成功时应用的函数。然后你可以减少那个列表。在通过重复调用 str 构建字符串的简单情况下,您可以剪掉中间人一点,只需通过 apply 自己调用 str:

      (defn person-story [person]
        (let [tests [[:showaddress #(format " I live in %s." (:address %))]
                     [:showage #(format " I am %s yrs old." (:age %))]
                     [(comp seq :hobby) #(format " I like %s." (clojure.string/join ", " (:hobby %)))]]]
          (apply str (format "My name is %s %s." (:firstname person) (:lastname person))
                 (for [[test f] tests
                       :when (test person)]
                   (f person)))))
      

      【讨论】:

        猜你喜欢
        • 2022-12-09
        • 2011-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-15
        • 2019-01-05
        • 2013-04-12
        • 2014-08-13
        相关资源
        最近更新 更多