clojure中的地图给出了意想不到的结果
在clojure中使用map,检查字符串是否包含大写字符。
(map #(= (clojure.string/upper-case %) %) "Hello")
预期的结果。
(true false false false false)
(true false false false false)
不幸的是,结果出乎意料。
(false false false false false)
我做了一个实验,当我在第一个“%”中替换“H”时,结果仍然出乎意料。
(map #(= (clojure.string/upper-case "H") %) "Hello")
(false false false false false)
当我在第二个“%”中替换“H”时,结果发生了变化,这是预期的结果。
(map #(= (clojure.string/upper-case %) "H) "Hello")
(true false false false false)
那有什么问题?请随意发表评论。
回答
正如其他人指出的那样,将字符与字符串进行比较是行不通的。比较字符串将起作用:
(map #(= (clojure.string/upper-case %) (str %)) "Hello")
=> (true false false false false)
然而,这更直接:
(map #(Character/isUpperCase %) "Hello")
=> (true false false false false)
回答
您不能将 String 与 char 进行比较。由字符串组成的序列是一个字符列表。
(seq "Hello")
;; => (H e l l o)
(map class "Hello")
;; => (java.lang.Character java.lang.Character java.lang.Character java.lang.Character java.lang.Character)
所以在你的情况下,你的测试归结为
(= "H" H) ;; => false
这是错误的。
要使其工作,请尝试以下操作之一:
;; compare strings
(map #(= (clojure.string/upper-case %) (str %)) "Hello")
;; => (true false false false false)
;; compare chars
(map #(= (first (clojure.string/upper-case %)) %) "Hello")
;; => (true false false false false)
回答
这是因为您错误地假设map将字符串"Hello"分解为,("H" "e" "l" "l" "o")但事实并非如此!
尝试:
(map identity "Hello") ;; => (H e l l o)
因此 map 将字符串分解为字符列表而不是单个字符串的列表。
所以你(map #(= (clojure.string/upper-case %) %) "Hello")正在比较
(clojure.string/upper-case H)哪个结果"H"与H. 由于一个是单个字符串,另一个是字符,结果是false- 因为类型不同。
(map #(= (clojure.string/upper-case %) (str %)) "Hello")
但是,您对原始代码的期望是什么。它返回:
功能
最有效的方法可能是使用正则表达式:
(defn has-upper-case? [s] (boolean (re-find #"[A-Z]" s)))
不太严格(不返回布尔值,而是从左到右的字符串的第一个上单字符串,或者nil如果没有找到):
(defn has-upper-case? [s] (re-find #"[A-Z]" s))
- @madeinQuant The point of using Regex is that it makes `map` superfluous. `re-find` stops scanning as soon as it sees the first upper character in the string. No further character then is examined -> thus contributing to performance. So when using regex, you can input the entire string at once - and the scanning will end as soon as it finds first match.