Как создать карту поиска в Scala - PullRequest
5 голосов
/ 26 июля 2011

Хотя я знаю, что есть несколько способов сделать это, меня больше всего интересует поиск наиболее идиоматического и функционального метода Scala.

Учитывая следующий банальный пример:

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

Каков наилучший способ создания неизменяемой карты поиска user.id -> User, чтобы я мог быстро выполнять поиск по user.id.

В Java я бы, вероятно, использовал карты Google 100-* .uniqueIndex хотя его уникальное свойство мне наплевать.

Ответы [ 5 ]

5 голосов
/ 26 июля 2011

Вы можете сохранить пользователей в списке и использовать list.find:

users.find{_.id == "3"} //returns Option[User], either Some(User("3")) or None if no such user

или, если вы хотите использовать карту, сопоставьте список пользователей со списком из двух кортежей, а затем используйтеметод toMap:

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

, который возвращает неизменную карту [String, User], затем вы можете использовать

umap contains "1" //return true

или

umap.get("1") //returns Some(User("1"))
4 голосов
/ 26 июля 2011

Если вы уверены, что все идентификаторы уникальны, канонический путь -

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

, как сказал @Dan Simon.Однако, если вы не уверены, что все идентификаторы уникальны, то канонический способ:

users.groupBy(_.id)

Это сгенерирует сопоставление идентификаторов пользователей с списком пользователей, которые используют этот идентификатор.

Таким образом, существует альтернативный не полностью канонический способ создания карты из идентификатора для отдельных пользователей:

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

Для опытных пользователей, которые хотят избежать промежуточного этапа созданиякарта списков или список, который затем превращается в карту, есть удобный метод scala.collecion.breakOut, который создает желаемый тип, если есть простой способ сделать это.Тем не менее, он должен знать тип, так что это поможет:

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

(Вы также можете назначить переменную или переменную указанного типа.)

1 голос
/ 23 апреля 2014

Преобразование списка в карту и использование его в качестве функции:

  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
0 голосов
/ 26 июля 2011

Карты также являются функциями, их метод apply обеспечивает доступ к значению, связанному с конкретным ключом (или исключение NoSuchElementException для неизвестного ключа), так что это обеспечивает очень чистый синтаксис поиска.Следуя ответу Дэна Саймона и используя более семантически значимое имя:

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

, которое затем предоставляет следующий синтаксис поиска:

scala> val user2 = Users("2")
user2: User = User(2)
0 голосов
/ 26 июля 2011

Если вы хотите использовать числовой индекс:

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)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...