根据以下条件更改本地的自觉方法是什么?在这里,我根据某些条件改变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的方法:
(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"
答案 0 :(得分:2)
从Clojure 1.5开始,cond->
/ cond->>
就像->
/ ->>
一样,条件决定是否执行单步:
(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
的事实。
答案 1 :(得分:1)
为了避免重复任何无用的事情(例如,如果条件,或者您正在浏览所有内容的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)))))