4
votes

Scala - Comparaison de collection - Pourquoi Set (1) == ListSet (1)?

Pourquoi la sortie de cette comparaison produit-elle true?

import scala.collection.immutable.ListSet

Set(1) == ListSet(1) // Expect false

//Output
res0: Boolean = true 

Et dans un sens plus général, comment la comparaison est-elle réellement effectuée?


2 commentaires

Cela ne vaut rien que l'implémentation se résume à set1.forall (set2.contains) (après une vérification de la taille, etc.), ce qui signifie que si vous comparez de grands ensembles et que vous vous souciez des performances, le ListSet doit venir en premier.


… Par exemple (0 à 100000) .to [Set] == ​​(0 à 100000) .to [ListSet] prend ~ 14 secondes sur mon ordinateur portable, tandis que l'inverse est instantané.


3 Réponses :


3
votes

Documentation Scala 2.12.8 :

Cette classe implémente des ensembles immuables en utilisant des données basées sur des listes structure.

ListSet est donc aussi un ensemble mais avec une implémentation concrète (basée sur des listes).


0 commentaires

4
votes

De Égalité des collections Scala :

Les bibliothèques de collections ont une approche uniforme de l'égalité et du hachage. L'idée est, tout d'abord, de diviser les collections en ensembles, cartes et séquences.

...

Par contre, au sein d'une même catégorie, les collections sont égales si et seulement si elles ont les mêmes éléments

Dans votre cas, les deux collections sont considérées comme des ensembles et elles contiennent les mêmes éléments, par conséquent, elles sont égales.


2 commentaires

C'est correct, mais juste une mise en garde pour les séquences: List (1, 2, 3) == Vector (1, 2, 3) mais List (1, 2, 3) ! = Array (1, 2, 3) et Array (1, 2, 3)! = Array (1, 2, 3) - voir aussi stackoverflow .com / questions / 29008500 /…


Array ne fait pas partie du package collections , il y a plus d'informations ici sur les particularités de Array . S'il est converti en Seq [Int] (qui l'envelopperait comme un WrappedArray ), alors il sera égal à une List équivalente



7
votes

Étant donné que la chaîne d'héritage Set <: genset gensetlike> est un peu longue, il n'est peut-être pas immédiatement évident de savoir où chercher le code de est égal à , donc je j'ai pensé peut-être le citer ici:

GenSetLike.scala :

  /** Compares this set with another object for equality.
   *
   *  '''Note:''' This operation contains an unchecked cast: if `that`
   *        is a set, it will assume with an unchecked cast
   *        that it has the same element type as this set.
   *        Any subsequent ClassCastException is treated as a `false` result.
   *  @param that the other object
   *  @return     `true` if `that` is a set which contains the same elements
   *              as this set.
   */
  override def equals(that: Any): Boolean = that match {
    case that: GenSet[_] =>
      (this eq that) ||
      (that canEqual this) &&
      (this.size == that.size) &&
      (try this subsetOf that.asInstanceOf[GenSet[A]]
       catch { case ex: ClassCastException => false })
    case _ =>
      false
  }

Essentiellement, il vérifie si l'autre objet est également un GenSet , et si oui , il tente d'effectuer des vérifications rapides (comme comparer size et appeler canEqual ), et si les tailles sont égales, il vérifie si cet ensemble est un sous-ensemble d'un autre set, vraisemblablement en vérifiant chaque élément.

Ainsi, la classe exacte utilisée pour représenter l'ensemble au moment de l'exécution n'est pas pertinente, ce qui compte c'est que l'objet comparé soit également un GenSet et qu'il ait les mêmes éléments.


0 commentaires