Vector 更新clojure中地图向量中的一个地图
我在这方面做了很多研究,但没有找到我的具体问题的答案。作为背景,我正在参加一个关于Java的编码训练营,我们正在学习Java旁边的JavaScript和Clojure。课程内容大致为Java:50%/JavaScript 30%/Clojure 20%。我已经超越了我的同班同学,正在应对来自老师的挑战 我在Clojure中构建了一个应用程序来管理动物收容所。我使用hashmaps向量作为我的中央数据存储。我成功做到的事情:Vector 更新clojure中地图向量中的一个地图,vector,clojure,hashmap,Vector,Clojure,Hashmap,我在这方面做了很多研究,但没有找到我的具体问题的答案。作为背景,我正在参加一个关于Java的编码训练营,我们正在学习Java旁边的JavaScript和Clojure。课程内容大致为Java:50%/JavaScript 30%/Clojure 20%。我已经超越了我的同班同学,正在应对来自老师的挑战 我在Clojure中构建了一个应用程序来管理动物收容所。我使用hashmaps向量作为我的中央数据存储。我成功做到的事情: 从hashmaps的硬编码数组加载样本数据 创建新动物并将其哈希映射添加
(defn edit-animals [animals]
;; ask which animal to edit index is 1 based from the UI
(let [index (wait-for-int "Please enter the idex of the animal to edit. Enter 0 to display the list of animals" 0 (count animals))]
;; if the user typed a valid index
(if (> index 0)
;; then edit the animal
(let [index (- index 1) ;; index is 0 based for indexing the array
animals animals
animal (nth animals index)
;; prompt with existing data and ask for new data
name (wait-for-string (str "Name: " (:name animal) "\n") false)
species (wait-for-string (str "Species: " (:species animal "\n")) false)
breed (wait-for-string (str "Breed: " (:breed animal "\n")) false)
description (wait-for-string (str "Description: " (:description animal "\n")) false)
;; check for null returns from user
name2 (if (= name "") (:name animal) name)
species2 (if (= species "") (:species animal) species)
breed2 (if (= breed "") (:breed animal) breed)
description2 (if (= description "") (:description animal) description)
;; update local copy of animal
animal (assoc animal :name name2 :species species2 :breed breed2 :description description2)]
;; assoc fails to update animals
;; assoc-in crashes at runtime
animals (assoc animals index animal))
;;(wait-for-enter "\nPress enter to return to the menu")
;; else dispolay the list of animals
(display-animals animals)))
animals)
我已在调试器中运行了此代码,并验证了在以下行中,所有内容均按预期工作:
animal (assoc animal :name name2 :species species2 :breed breed2 :description description2)
正如我在评论中记录的那样,下一行有两种方式失败
我知道atom可能是一种更好的方法,但到目前为止,不断传递的映射向量是有效的,所以我想找到一个解决我当前问题的方法,不涉及使用atom。一旦我解决了这个问题,我计划将项目切换到原子数据结构。但这是另一天的计划
如果我错过了这里的相关讨论,请为我指出正确的方向 我想你想把
动物
从
animals (assoc animals index animal))
在if
语句的末尾,返回函数的结果
(assoc animals index animal)
或者展示它们
(display-animals (assoc animals index animal))
简而言之,您必须返回绑定在最内层let中的动物(它的索引>0),否则显示当前动物并返回它。所以它是这样的:
(defn edit-animals []
(let [index ...]
(if (> index 0)
;; for an acceptable index you query for input, modify animals, and return modified collection
(let [...]
(assoc animals index animals))
;; otherwise display initial data and return it
(do (display animals)
animals))))
但我会对代码进行更多的重组,使其更具clojure风格。首先,我将使用独立函数的输入提取动物的更新,以删除使let
绑定混乱的name、name2、breed、breed2…
绑定。(upd和input
),并将assoc
替换为update
。大概是这样的:
(defn edit-animals [animals]
(letfn [(upd-with-input [animal field prompt]
(let [val (wait-for-string (str prompt (field animal) "\n") false)]
(if (clojure.string/blank? val)
animal
(assoc animal field val))))]
(let [index (dec (wait-for-int "enter index" 0 (count animals)))]
(if (contains? animals index)
(update animals index
(fn [animal]
(-> animal
(upd-with-input :name "Name: ")
(upd-with-input :species "Species: ")
(upd-with-input :breed "Breed: ")
(upd-with-input :description "Description: "))))
(do (when (== -1 index) (display animals))
animals)))))
然后我会考虑将收集用户输入的整个部分与实际更新动物收集分离。行:
animals (assoc animals index animal))
它不做你认为它做的事情——它不在let绑定向量中
首先,干得好,你问问题的方式正确(举例说明等)。祝贺你上了编码课程。我的建议是继续做你正在做的事情,并学会用clojure以一种与java截然不同的方式思考。它们都是值得的,只是方法不同而已。在代码中,您正在执行许多“临时分配”(例如name2
)。事实上,let绑定向量有11对,这表明你做得太多了。let
,动物中的第二项特别奇怪
相反,试着考虑表达式的计算,而不是赋值name2=name1+…
是一条语句,而不是表达式。它没有任何作用。相反,在声明式语言中,几乎所有内容都是表达式。在下面的代码中(我只是您所做工作的扩展,不一定是我从头开始做的),请注意没有本地绑定被重新绑定(没有任何内容被多次“分配到”)let
允许我们在词汇上将name
绑定到表达式的结果,然后使用name
实现其他功能<代码>非空
允许我们比使用名称
和名称2
做得更好,而这正是您所做的
(def animals [{:name "John" :species "Dog" :breed "Pointer" :description "Best dog"}
{:name "Bob" :species "Cat" :breed "Siamese" :description "Exotic"}])
(defn edit-animals
[animals]
(if-let [index (dec (wait-for-int "Please enter the index of the animal to edit. Enter 0 to display the list of animals" 0 (count animals)))]
(let [animal (nth animals index)
name (or (not-empty (wait-for-string (str "Name: " (:name animal) "\n") false))
(:name animal))
species (or (not-empty (wait-for-string (str "Species: " (:species animal) "\n") false))
(:species animal))
breed (or (not-empty (wait-for-string (str "Breed: " (:breed animal) "\n") false))
(:breed animal))
description (or (not-empty (wait-for-string (str "Description: " (:description animal) "\n") false))
(:description animal))
animal {:name name :species species :breed breed :description description}]
(println "showing new animal: " animal)
(assoc animals index animal))
animals))
(def animals (edit-animals animals))
请注意,除了重新构造代码之外,这并不能真正实现很多其他功能。它确实做得太多了,并且不是一个函数应该如何做好一件事的好例子。但我认为你现在的目标应该是在写clojure的时候更加地道一点,摆脱命令式思维。这样做之后,您就可以专注于它的设计部分了
继续努力,问更多的问题 您需要重新构造代码,因为您不返回更新后的值,而是返回初始值。记住集合是不可变的,我同意我需要重新构造代码。我只是不知道该怎么做。。。我尝试将最后一行
animals(assoc animals index animal))
移到big(let[]…0
语句中,但得到了完全相同的结果。简言之,您必须返回绑定在最内层let
(it index>0)中的animals
,否则显示当前的动物
并返回它。因此,它将是这样的:(如果(>索引0)(让[…](关联动物索引动物))(do(显示动物)动物))
但我更愿意对其进行进一步的重组,使其更具可读性,减少必要性。我对这个问题的评论感激不尽!我赞同letwinski的解决方案,但发现leetwinski和Josh的贡献对解决这个问题和另一个我从未发布过的问题极为有价值,因为我最终能够解决这个问题谢谢。你给了我一些糊涂的东西。我同意我没有把事情做得很完美。这是我的第一个Culjury项目,我知道我还有一条路要走,在我真正精通之前。很好的工作。顺便说一下,在这里至少考虑一下你的答案,你已经发现我们帮助了提姆。整个上午我都在上课。我的老师确实把这篇文章带到了学校