47 votes

Pourquoi y a-t-il tant de fonctions de construction de cartes dans le clojure?

Question de novice, mais je ne comprends pas vraiment pourquoi il y a tant d’opérations de construction de cartes en clojure.

Vous avez conj , assoc et merge , mais semble-t-il faire plus ou moins la même chose?

 (assoc {:a 1 :b 2} :c 3)
(conj {:a 1 :b 2} {:c 3})
(merge {:a 1 :b 2} {:c 3})
 

Quelle est vraiment la différence et pourquoi toutes ces méthodes sont-elles nécessaires quand elles font plus ou moins la même chose?

52voto

dbyrne Points 18604

assoc et conj se comportent très différemment pour d'autres structures de données:

user=> (assoc [1 2 3 4] 1 5)
[1 5 3 4]
user=> (conj [1 2 3 4] 1 5)
[1 2 3 4 1 5]

Si vous écrivez une fonction qui permet de gérer plusieurs types de collections, alors votre choix fera une grande différence.

Traiter merge comme les cartes seule fonction (qui est similaire à conj pour les autres collections).

Mon avis:

  • assoc utiliser lorsque vous êtes en train de "changer" existant de paires clé/valeur
  • conj - utiliser lorsque vous êtes "ajout" de nouvelles paires clé/valeur
  • fusion - utiliser lorsque vous êtes à la combinaison de deux ou plus de cartes

23voto

Michał Marczyk Points 54179

En fait, ces fonctions se comportent très différemment lorsqu'il est utilisé avec des cartes.

  1. conj:

    Tout d'abord, l' (conj {:a 1 :b 2} :c 3) exemple de texte de la question ne fonctionne pas du tout (ni avec 1,1 ni de 1,2 IllegalArgumentException est jeté). Il y a juste une poignée de types qui peuvent être conjed sur des cartes, à savoir les deux éléments les vecteurs, clojure.lang.MapEntrys (qui sont en fait l'équivalent de deux éléments vecteurs) et les cartes.

    Notez que seq d'une carte comprend un tas d' MapEntrys. Ainsi, vous pouvez faire par exemple

    (into a-map (filter a-predicate another-map))
    

    (à noter qu' into utilise conj -- ou conj!, quand c'était possible-à l'interne). Ni merge ni assoc vous permet de le faire.

  2. merge:

    C'est presque exactement équivalent à conj, mais il remplace son nil arguments avec {} -- de hachage vide cartes -- et va donc retourner une carte lors de la première "carte" dans la chaîne arrive à être nil.

    (apply conj [nil {:a 1} {:b 2}])
    ; => ({:b 2} {:a 1}) ; clojure.lang.PersistentList
    (apply merge [nil {:a 1} {:b 2}])
    ; => {:a 1 :b 2} ; clojure.lang.PersistentArrayMap
    

    Remarque il n'y a rien (à l'exception de la docstring...) pour arrêter le programmeur de l'aide d' merge avec d'autres types de collection. Si on fait ça, la folie s'ensuit; pas recommandé.

  3. assoc:

    Encore une fois, l'exemple de la question du texte -- (assoc {:a 1 :b 2} {:c 3}) -- ne fonctionne pas; au lieu de cela, il va jeter un IllegalArgumentException. assoc prend une carte argument suivi par un même nombre d'arguments, ceux en position impaire (disons que la carte est à la position 0) sont les clés, ceux à même les postes sont des valeurs. Je trouve que j' assoc choses sur des cartes, plus souvent que je ne l' conj, même si quand j' conj, assoc permettrait de se sentir lourd. ;-)

  4. merge-with:

    Par souci d'exhaustivité, c'est la dernière fonction de base traitant avec des cartes. Je trouve qu'il est extrêmement utile. Il fonctionne comme la docstring indique; voici un exemple:

    (merge-with + {:a 1} {:a 3} {:a 5})
    ; => {:a 9}
    

    Notez que si la carte contient une "nouvelle" la clé, ce qui n'a pas eu lieu dans les cartes à gauche de la fonction de fusion ne sera pas appelé. C'est parfois frustrant, mais en 1.2 un savant reify peut fournir une carte avec des non-nil "valeurs par défaut".

6voto

mikera Points 63056

Depuis que les cartes sont un omniprésente de la structure de données en Clojure, il est logique d'avoir de multiples outils pour les manipuler. Les différentes fonctions sont toutes syntaxiquement pratique dans des circonstances légèrement différentes.

Mon point de vue personnel sur les fonctions spécifiques que vous mentionnez :

  • J'utilise assoc pour ajouter une valeur unique pour une carte donnée, une clé et une valeur
  • J'utilise de fusion de combiner deux cartes ou ajouter plusieurs nouvelles entrées à la fois
  • Je n'ai généralement pas de conj avec des cartes à tous, comme je l'associe mentalement avec des listes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X