从 clojure 中的数组构建哈希图

building a hashmap from an array in clojure

首先,我是 Iron Yard 12 周第 5 周的学生,学习 Java 后端工程。该课程由大约 60% Java、25% JavaScript 和 15% Clojure 组成。

我遇到了以下问题(在评论中概述):

;; Given an ArrayList of words, return a HashMap> containing a keys for every
;; word's first letter. The value for the key will be an ArrayList of all
;; words in the list that start with that letter. An empty string has no first
;; letter so don't add a key for it.
(defn index-words [word-list]
  (loop [word (first word-list)
         index {}]
    (if (contains? index (subs word 0 1))
      (assoc index (subs word 0 1) (let [words (index (subs word 0 1))
                                         word word]
                                     (conj words word)))
      (assoc index (subs word 0 1) (conj nil word)))
    (if (empty? word-list)
      index
      (recur (rest word-list) index))))

我在使用 zipmap 时遇到了类似的问题,但我确信我在这个问题上遗漏了一些东西。代码编译但无法 运行.

具体来说,我未能在 'if' 的 false 子句中更新我的 hashmap 索引。

我已经在 REPL 中测试了这个函数的所有组件,它们是独立工作的。但我正在努力将它们放在一起。

这里是调用word-list的代码,供大家参考。

  (let [word-list ["aardvark" "apple" "zamboni" "phone"]]
    (printf "index-words(%s) -> %s\n" word-list (index-words word-list)))

与其从社区获得可行的解决方案,我更希望得到一些指导,让我的大脑朝着正确的方向前进。

函数assoc不修改index。您需要使用 assoc returns 的新值。 conj 也是如此:它不会修改您传递给它的地图。

我希望,这个答案是您期望得到的答案:只是您问题所在的一个指针。

顺便说一句:如果你可以用 PersistentList 来做,那么当使用 reduce 而不是 looprecur 时,这就变成了一行。对您来说,一个有趣的函数可能是 update-in.

玩得开心 Clojure。

group-by 函数可以满足您的要求。

  • 您可以使用 first 作为其判别函数参数。它 returns 字符串的第一个字符,如果没有则 nil(first word)(subs word 0 1).
  • 更简单
  • 使用 dissoc 删除键 nil 的条目。

你很少需要在 clojure 中使用明确的 loops。大多数常见的控制模式已在 group-by 等函数中捕获。这些函数具有函数和可能的集合参数。最常见的示例是 mapreduceClojure cheat sheet 是对他们最有用的指南。