【问题标题】:map in clojure giving unexpected resultclojure 中的地图给出了意想不到的结果
【发布时间】:2021-04-23 09:52:03
【问题描述】:

在clojure中使用map,检查字符串是否包含大写字符。

(map #(= (clojure.string/upper-case %) %) "Hello") 

预期的结果。

(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)

这有什么问题?请随时发表评论。

【问题讨论】:

  • 您说您需要检查字符串是否包含大写字符,所以我假设您不需要知道哪个是正确的吗?在这种情况下,为什么不检查整个字符串呢? (= (str/lower-case "Hello") "Hello") 应该告诉你你的字符串最初是否是小写的
  • 这是程序的一小部分,由于某些原因,我需要一个字符一个字符地检查一个长字符串。
  • 您将字符串与字符进行比较,您的测试实际上如下所示:(= "H" \H) 这是错误的。
  • 下面有一些很好的答案。您可能还对tupelo.chars (cljdoc.org/d/tupelo/tupelo/21.04.13/api/tupelo.chars) 和tupelo.string (cljdoc.org/d/tupelo/tupelo/21.04.13/api/tupelo.string) 中的帮助和便利功能感兴趣

标签: dictionary clojure


【解决方案1】:

正如其他人所指出的,将字符与字符串进行比较是行不通的。比较字符串会起作用:

(map #(= (clojure.string/upper-case %) (str %)) "Hello")
=> (true false false false false)

不过这样更直接:

(map #(Character/isUpperCase %) "Hello")
=> (true false false false false)

【讨论】:

  • 感谢您的帮助,将您的评论与正则表达式结合起来。我找到了答案。
【解决方案2】:

这是因为您错误地假设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")

但是,您对原始代码的期望是什么。 它返回:

(true false false false false)

功能

最有效的方法可能是使用正则表达式:

(defn has-upper-case? [s] (boolean (re-find #"[A-Z]" s)))

不太严格(不返回布尔值,而是从左到右的字符串的第一个高位单个字符串或nil,如果没有找到):

(defn has-upper-case? [s] (re-find #"[A-Z]" s))

【讨论】:

  • 你可以直接使用条件作为真/假值,而不是(如果条件为真假),或者,如果你真的想要一个布尔结果,像这样包装它:(布尔条件)-这将严格返回真或假。
  • @SeanCorfield,我在哪里可以找到您建议的示例?
  • 关注您的评论,而不是“if”语句,我直接使用字符或 nil 值。 (map #(re-find #"[A-Z]" (str %)) "Hello"),谢谢你的帮助,
  • @madeinQuant 没错,我只是想遵循? 函数实际上必须返回一个布尔值的约定——不是吗? - (if (re-find #"[A-Z]" "Hello") true false) 真的会返回 truefalse 而没有 if clouses,它会返回 "H"(一些字符串)或 nil
  • @madeinQuant 使用正则表达式的关键在于它使map 变得多余。 re-find 一看到字符串中的第一个大写字符就停止扫描。然后没有进一步的字符被检查 -> 从而有助于性能。因此,当使用正则表达式时,您可以一次输入整个字符串 - 一旦找到第一个匹配项,扫描就会结束。
【解决方案3】:

您不能将字符串与字符进行比较。由字符串组成的序列是一个字符列表。

(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)

【讨论】:

  • 感谢您的评论,您的回答帮助我理清了 Clojure 中数据结构的一些概念。
【解决方案4】:

upper-case 将字符串全部转换为大写。

参考:https://clojuredocs.org/clojure.string/upper-case

你需要使用类似的东西:

 (some #(Character/isUpperCase %) "Hello") => true
 (some #(Character/isUpperCase %) "hello") => nil

【讨论】:

    【解决方案5】:

    你被clojure.string/upper-case的无证行为所吸引:

    • 它适用于任何对象,而不仅仅是字符串。
    • 它总是返回一个字符串。

    例如,

    (clojure.string/upper-case +)
    => "CLOJURE.CORE$_PLUS_@19CFE007"
    

    如果您查看the source code,您会发现它在.toUpperCase 之前应用了.toString

    所以它也适用于单个字符。但它返回一个字符串,而不是 - 我所期望的 - 一个字符:

    (clojure.string/upper-case 1)
    => "1"
    

    补救方法是对整个字符串应用upper-case,然后使用map= 将原始字符串与转换后的字符串逐个字符进行比较:

    (#(map = (clojure.string/upper-case %) %) "Hello")
    => (true false false false false)
    

    或者,使用(fn [...] ...) 代替#(...)

    ((fn [coll] (map = (clojure.string/upper-case coll) coll)) "Hello")
    => (true false false false false)
    

    【讨论】:

    • 感谢您的评论。我可以问个问题吗?为什么在map前面加一个set“#”操作符,在map后面做一个比较“=”?
    • @madeinQuant #( ... )anonymous function literal - 用于编写小函数的简写。您在问题的第一行代码中自己使用了它。我将更改答案以改用fn
    • @madeinQuant map 后面的= 将原始字符串与转换后的字符串逐个字符进行比较。 = 后跟两个集合,因此作为两个参数的函数调用。例如,(map + [1 2 3] [4 5 6]) 产生 (5 7 9)
    猜你喜欢
    • 2019-05-19
    • 2017-01-05
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2021-04-22
    • 2016-02-13
    • 2017-11-05
    相关资源
    最近更新 更多