5 votes

Comment créer une carte de recherche en Scala

Alors que je sais qu'il y a quelques façons de le faire, je suis surtout intéressé à trouver la méthode Scala la plus idiomatique et fonctionnelle.

Étant donné l'exemple banal suivant :

case class User(id: String)
val users = List(User("1"), User("2"), User("3"), User("4")) 

Quelle est la meilleure façon de créer une Map de recherche immutable de user.id -> User pour pouvoir effectuer des recherches rapides par user.id.

En Java, j'utiliserais probablement la méthode Maps.uniqueIndex de Google Collections même si sa propriété unique m'importe peu.

6voto

Dan Simon Points 5408

Vous pouvez garder les utilisateurs dans une liste et utiliser list.find :

users.find{_.id == "3"} //retourne Option[User], soit Some(User("3")) soit None si aucun utilisateur n'existe

ou si vous voulez utiliser une Map, mappez la liste des utilisateurs vers une liste de 2-tuples, puis utilisez la méthode toMap :

val umap = users.map{u => (u.id, u)}.toMap

ce qui retournera une Map[String, User] immuable, ensuite vous pouvez utiliser

umap contains "1" //retourne true

ou

umap.get("1") //retourne Some(User("1"))

4voto

Rex Kerr Points 94401

Si vous êtes sûr que tous les IDs sont uniques, la manière canonique est

users.map(u => (u.id, u)).toMap

comme l'a dit @Dan Simon. Cependant, si vous n'êtes pas sûr que tous les IDs sont uniques, alors la manière canonique est:

users.groupBy(_.id)

Cela générera une correspondance des IDs d'utilisateur à une liste d'utilisateurs qui partagent cet ID.

Ainsi, il existe une autre manière pas entièrement canonique de générer la carte de l'ID vers des utilisateurs uniques:

users.groupBy(_.id).mapValues(_.head)

Pour les utilisateurs experts qui veulent éviter l'étape intermédiaire de créer une carte de listes, ou une liste qui est ensuite transformée en carte, il existe la méthode pratique scala.collecion.breakOut qui construit le type que vous voulez s'il y a un moyen simple de le faire. Il a besoin de connaître le type, cependant, donc ceci fonctionnera:

users.map(u => (u.id,u))(collection.breakOut): Map[String,Utilisateur]

(Vous pouvez également assigner à une variable de type spécifié.)

1voto

LRLucena Points 150

Convertir la liste en une carte et l'utiliser comme une fonction :

  case class User(id: String)
  val users = List(User("1"), User("2"), User("3"))

  val usersMap = users map { case user @ User(id) => id -> user } .toMap

  usersMap("1")    // Some(User("1"))
  usersMap("0")    // None

0voto

user unknown Points 15555

Si vous souhaitez utiliser un index numérique :

scala> users.map (u=> u.id.toInt -> u).toMap 
res18: scala.collection.immutable.Map[Int,User] =
  Map((1,User(1)), (2,User(2)), (3,User(3)))

0voto

Don Mackenzie Points 3639

Les cartes sont également des fonctions, leur méthode apply permet d'accéder à la valeur associée à une clé particulière (ou une NoSuchElementException est levée pour une clé inconnue), ce qui permet d'obtenir une syntaxe de recherche très propre. En reprenant la réponse de Dan Simon et en utilisant un nom ayant plus de sens sémantiquement :

scala> val utilisateurs = utilisateurs map {u  => (u.id, u)} toMap      
Utilisateurs: scala.collection.immutable.Map[String,User] = Map((1,User(1)), (2,User(2)), (3,User(3)))

ce qui fournit ensuite la syntaxe de recherche suivante :

scala> val utilisateur2 = utilisateurs("2")
utilisateur2: User = User(2)

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