0
votes

Comment "filtrer" correctement les cartes dans Clojure?

Je joue avec Clojure depuis un moment et je me suis retrouvé coincé dans quelque chose que je trouve très trivial pour beaucoup ... mais pas moi. J'ai le morceau de code suivant;

;; Define a Record structure
(defrecord Person [first-name last-name age occupation])

(def john (->Person "John" "Frusciante" 50 "Guitarist"))

;; People map
(def people {"1" john
             "2" (->Person "Pablo" "Neruda" 90 "Poet")
             "3" (->Person "Stefan" "Zweig" 120 "Author")
             }
) 

(defn get-120-year-old-guy
  [peeps]
  (filter #(= (:age %) 120) peeps)
)

(println "who's 120?: " (get-120-year-old-guy people))

Cet appel renvoie une liste vide. Je sais que c'est quelque chose qui ne va pas dans la façon dont je récupère la valeur mais je ne peux pas voir ce que c'est exactement.


0 commentaires

3 Réponses :


8
votes

Vous pouvez avoir une idée de ce qui se passe en modifiant temporairement la fonction:

(defn get-120-year-old-guy [peeps]
  (filter (comp  ; And (comp)ose all three checks together
             #{120}  ; Then test if it's in the set of #{120}
             :age  ; Then get the age
             val)  ; Get the value from the MapEntry
           peeps))

Impressions:

(filter (comp #{120} :age val) people)

Notez comment chaque entrée est une MapEntry . Dans votre tentative, vous appliquez :age à l'ensemble de MapEntry (qui renvoie nil ), pas seulement à la personne.

Je pense que la déstructuration à l'aide d'une fonction anonyme complète serait le moyen le plus simple:

who's 120?:  ([3 #user.Person{:first-name Stefan, :last-name Zweig, :age 120, :occupation Author}])

Les sorties:

(defn get-120-year-old-guy
  [peeps]
  (filter (fn [[_ person]] (= (:age person) 120)) peeps))

@leetwinski signale une solution plus idiomatique qui supprime complètement la fonction explicite:

(clojure.lang.MapEntry [1 #user.Person{:first-name John, :last-name Frusciante, :age 50, :occupation Guitarist}]
clojure.lang.MapEntry [2 #user.Person{:first-name Pablo, :last-name Neruda, :age 90, :occupation Poet}]
clojure.lang.MapEntry [3 #user.Person{:first-name Stefan, :last-name Zweig, :age 120, :occupation Author}]
)

En panne:

(defn get-120-year-old-guy
  [peeps]
  (filter (fn [m] (println (type m) m)) peeps))


4 commentaires

ou juste (filter (comp #{120} :age val) people)


@leetwinski Ya, c'est vrai. Pour être honnête, je n'ai pas écrit Clojure depuis deux ans maintenant. Je suis super rouillé.


sensationnel. @Carcigenicate vers quoi êtes-vous passé? si ce n'est pas un secret)


@leetwinski Je suis à l'école pour la sécurité de l'information, donc je suis passé à Python, C et l'assemblage pour le bien du cours. Je vous le dis, il est difficile de passer d'un langage courant et succinct comme Clojure à C.



3
votes

Si vous regardez le premier élément de votre carte externe, vous verrez que chaque élément est un clojure.lang.MapEntry d'une chaîne à une personne. La clé est "1" et la valeur est un enregistrement Personne:

(defn get-120-year-old-guy
  [peeps]
  (filter #(= (:age (val %)) 120) peeps)
)

> (println "who's 120?: " (get-120-year-old-guy people))
who's 120?:  ([3 #challenges.anag.Person{:first-name Stefan, :last-name Zweig, :age 120, :occupation Author}])

Pour filtrer sur le champ: age, vous devez d'abord obtenir la valeur de la paire {clé, valeur}. Une façon consiste à utiliser la fonction val pour obtenir cela avant d'obtenir: age à partir de la carte Person. Votre fonction de filtrage est alors:

> (first people)
["1"
 {:first-name "John",
  :last-name "Frusciante",
  :age 50,
  :occupation "Guitarist"}]


0 commentaires

0
votes

Une autre option consiste à déstructurer le clojure.lang.MapEntry :

(defn get-120-year-old-guy
  [peeps]
  (filter (fn [[_ v]] (= (:age v) 120)) peeps)
)

Ici vous pouvez voir (fn [[_ v]] ... où le _ est utilisé comme espace réservé pour la key inutilisée.


0 commentaires