为什么这个关键字函数查找在哈希图中不起作用?

Why doesn't this keyword function lookup work in a hashmap?

我想我需要一些眼球才能对此有所了解

    (println record)
    (println (keys record) " - " (class record) " : " (:TradeId record) (:Stock record))
    (doall  (map #(println "Key " % "Value " (% record)) (keys record)))

输出:

{:Stock ATT, :AccountId 1, :TradeId 37, :Qty 100, :Price 117, :Date 2011-02-24T18:30:00.000Z, :Notes SPLIT 1:10, :Type B, :Brokerage 81.12}

(:Stock :AccountId :TradeId :Qty :Price :Date :Notes :Type :Brokerage)  -  clojure.lang.PersistentHashMap  :  nil ATT

Key  :Stock Value  ATT
Key  :AccountId Value  1
Key  :TradeId Value  37
...

问题是 (:TradeId record) 即使它作为密钥存在也不起作用。遍历所有键和值 - 第 3 行 - 产生正确的值。 尝试重命名 csv 中的列,但行为没有变化。除了这是 csv 中的第一列之外,我看不出与其他列(哪些有效)有什么不同。

哈希图是从这样的代码创建的——从 CSV 中读取记录。 clojure.data.csv 包中的标准代码。

(->> (csv/read-csv reader)
           csv-data->maps
           (map #(my-function some-args %))
           doall))


(defn csv-data->maps 
  "Return the csv records as a vector of maps"
  [csv-data]
  (map zipmap
       (->> (first csv-data) ;; First row is the header
            (map keyword) ;; Drop if you want string keys instead
            repeat)
       (rest csv-data)))

我会尝试两件事。首先,打印每个键的类型。它们应该都是 clojure.lang.Keyword,如果您包含的创建代码是准确的并且 my-function 保留了它们的类型;但是如果您以其他方式创建它并且记错了,您可能会发现该键是一个符号,或者一个字符串或类似的东西。一般来说,不要在字符串以外的任何东西上使用 println,因为它的保真度很低。 prn 可以更好地传达您的数据的准确图片 - 它并不完美,但至少您可以使用它从关键字中分辨出字符串。

其次,更仔细地查看打印值,例如使用 od -t x1 - 或者你可以在过程中使用类似的东西来完成它:

(let [k (key (first m)), s (name k)]
  (clojure.string/join " " 
                       (for [c s] 
                         (format "%02x" (int c)))))

如果结果不是 "53 74 6f 63 6b",那么您的文件中有一些奇怪的字符 - 可能是非打印字符,可能是一些看起来像大写字母 S 但实际上不是的字符。

一旦我到了尝试任何东西的地步,我就从 REPL 中复制关键字并将其粘贴到 VSCode 中,果然 - 关键字中有这个看起来很奇怪的字符 :?Id。使用 weird 关键字,查找有效。

解决方法:添加一个虚拟列作为第一列。

然后事情开始顺利,我记得在 csv reader 项目文档中读过一些关于 BOM 的内容。 https://github.com/clojure/data.csv#byte-order-mark

下载了一个 hexdump 文件查看器,它确认了文件开头的问题字节。

o;?Id,AccountId,...

最终解决方案:在将 reader 传递给 data.csv 读取函数之前,跳过不需要的字节。

(.skip reader 1)

世界又变得有意义了。

“第一列”绝对可疑,它指向一些不可见的字符,例如 BOM 悄悄地附加到您的第一个关键字。

要调试,请尝试打印出关键字名称的十六进制。 And/or 如果您对输入文件的前几行进行十六进制转储,例如使用 head -n 2 file.csv | od -x,也许您会看到一些东西。