Estoy tratando de actualizar cada línea que tiene un "disfrutar-clojure"? que devuelve la "calificación de cordura" verdadera a -2 (es decir, la clasificación de cordura de johnny se actualizaría a -2)

(def student-database
  { 0 {:enjoy-clojure? false, :name "jimmy",:sanity-rating 9}
    1 { :enjoy-clojure? true, :name "johnny",:sanity-rating 2}
    2 { :enjoy-clojure? true, :name "jilly",:sanity-rating 5}
    3 { :enjoy-clojure? true, :name "janey",:sanity-rating 8}
    4 {:enjoy-clojure? false, :name "jelly",:sanity-rating 10}}) 

Soy nuevo en Clojure y he intentado investigar la actualización y la asociación y parece que realmente no puedo encontrar una manera de actualizar varios elementos ((assoc student-database [0 :sanity-rating] -2) solo devuelve las actualizaciones de un elemento). Para filtrar la base de datos de estudiantes para eliminar a los estudiantes que volvieron verdaderos, tengo

(defn unhinged?
 [record]
 (:enjoy-clojure? record))

(defn minus-two-students
 [student-database]
 (filter #(unhinged? %)
  (map student-database [0 1 2 3 4])))

Y vuelve

({:enjoy-clojure? true, :name "johnny", :sanity-rating 2} {:enjoy-clojure? 
   true, :name "jilly", :sanity-rating 5} {:enjoy-clojure? true, :name 
   "janey", :sanity-rating 8})

Lo cual funciona muy bien, pero también lo necesito para actualizar toda su calificación de cordura a -2. Cualquier ayuda / consejo sería muy apreciada.

1
Student1860 26 feb. 2018 a las 22:27

4 respuestas

La mejor respuesta

No dijo en su pregunta que desea que la función devuelva solo (= enjoy-clojure? true) registros, pero a partir de sus comentarios en las otras respuestas, creo que eso es lo que realmente quiere.

Entonces tal vez esto?

(defn unhinged?
  [record]
  (:enjoy-clojure? record))

(defn minus-two-students
  [student-database]
  (->> student-database
       vals
       (filter unhinged?)
       (map #(assoc % :sanity-rating -2))))

La salida será

({:enjoy-clojure? true, :name "johnny", :sanity-rating -2} 
 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2} 
 {:enjoy-clojure? true, :name "janey", :sanity-rating -2})
1
tap 27 feb. 2018 a las 00:07

Lo más simple sería así:

(reduce-kv (fn [acc idx row]
             (assoc acc idx
                    (if (:enjoy-clojure? row)
                      (assoc row :sanity-rating -2)
                      row)))
           {}
           student-database)

;;=> {0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9}, 
;;    1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2}, 
;;    2 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2}, 
;;    3 {:enjoy-clojure? true, :name "janey", :sanity-rating -2}, 
;;    4 {:enjoy-clojure? false, :name "jelly", :sanity-rating 10}}

También puedes hacer algo como esto:

(reduce-kv (fn [res k {ec? :enjoy-clojure?}]
             (if ec?
               (assoc-in res [k :sanity-rating] -2)
               res))
           student-database
           student-database)

;;=> {0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9}, 
;;    1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2}, 
;;    2 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2}, 
;;    3 {:enjoy-clojure? true, :name "janey", :sanity-rating -2}, 
;;    4 {:enjoy-clojure? false, :name "jelly", :sanity-rating 10}}
1
leetwinski 28 feb. 2018 a las 11:00

Para actualizar toda la base de datos, puede hacer:

(def student-database
  {0 {:enjoy-clojure? false, :name "jimmy",:sanity-rating 9}
   1 { :enjoy-clojure? true, :name "johnny",:sanity-rating 2}
   2 { :enjoy-clojure? true, :name "jilly",:sanity-rating 5}
   3 { :enjoy-clojure? true, :name "janey",:sanity-rating 8}
   4 {:enjoy-clojure? false, :name "jelly",:sanity-rating 10}})

(defn update-db [db]
  (zipmap (keys db)
          (map (fn [student]
                 (cond-> student
                   (:enjoy-clojure? student)
                   (assoc :sanity-rating -2)))
               (vals db))))

(update-db student-database) ;;=> 
{0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9}, 
 1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2} ...}
1
Michiel Borkent 26 feb. 2018 a las 19:40

¡Aquí viene la versión reduce-kv!

(defn adjust-sanity [student]
  (if (:enjoy-clojure? student)
    (assoc student :sanity-rating -2)
    student))

(reduce-kv (fn [m k v] (assoc m k (adjust-sanity v)))
           {}
           student-database)
=>
{0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9},
 1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2},
 2 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2},
 3 {:enjoy-clojure? true, :name "janey", :sanity-rating -2},
 4 {:enjoy-clojure? false, :name "jelly", :sanity-rating 10}}

O otra opción con una función auxiliar para actualizar todos los valores de un mapa:

(defn update-vals [m f]
  (reduce-kv (fn [m' k v] (assoc m' k (f v))) {} m))
(update-vals student-database adjust-sanity)
2
Taylor Wood 26 feb. 2018 a las 19:40