Элегантная реализация карты

#list #scala #collections #map #set

#Список #scala #Коллекции #словарь #установить

Вопрос:

имея список упорядоченных строк для сравнения с другим списком, я решил реализовать его в виде карты, в которой ключом является первый символ строки, а значением — список строк с тем же первым символом. Короче говоря, у меня есть что-то вроде этого:

 var list1:Map[Char, List[String]] = Map('a' -> List("alone", "away"))
var list2:List[String] = List("I", "am", "alone", "at", "home", "watching", "batman", "XD")
  

Теперь, после реализации моего кода таким образом, с ними «сложно» работать, пытаясь рассматривать первый как простой список, поэтому мне было интересно, есть ли другой, более элегантный способ решения этой проблемы.
Если мне нужно проверить, есть ли в list1 значение «alone», я должен сначала получить ключ ‘a’, а затем вызвать метод contains. Мне пришлось реализовать нечто подобное.

 if ( list1( "alone".charAt(0) ).contains( "alone" ) ) ...
  

Некрасиво каждый раз извлекать ключ, а затем сравнивать списки, и я хотел бы создать новую карту (или список), которая реализует это под капотом (она автоматически извлекает ключ, а затем работает со списком).).
Что вы предлагаете?
Спасибо.

РЕДАКТИРОВАТЬ: я переписал часть вопроса, уточнив некоторые моменты. Первый список упорядочен, второй — нет.

Комментарии:

1. у вас есть список упорядоченных строк? Или упорядоченный список строк? И почему у вас есть эта проводная карта? Почему бы не использовать простой список?

2. Ну, у меня есть список упорядоченных строк, и я реализовал свой код таким образом, полагая, что это может быть быстрее для выполнения поиска и замены и некоторых других вещей. Я имею в виду, что быстрее выполнять поиск в меньшем списке, чем во всем списке, нет?

3. Вероятно, вам лучше всего использовать Vector . Это довольно эффективно при подобных операциях.

4. В чем преимущества Vector? В документации scala-lang нет описания.

5. Я не знаком со scala, но не могли бы вы просто использовать наборы и их операции? — В любом случае.. В этом случае с отсортированными списками, почему бы не выполнить итерацию по одному списку, сравнивая каждый элемент с элементом в той же позиции в другом списке? O (n)

Ответ №1:

Из всего, что я видел, вам действительно нужен просто список. Поэтому используйте список. (Или, возможно, SortedSet http://www.scala-lang.org/api/current/scala/collection/SortedSet.html )

Похоже, вас беспокоит производительность, но вы не указываете, какая часть какого алгоритма должна замедляться, и насколько быстрее она должна выполняться, и не приводите убедительных аргументов в пользу того, что выбранный вами подход соответствует этим требованиям к производительности. Итак, еще раз: просто используйте список. Затем измерьте производительность. Если это действительно замедляется, создайте на его основе тестовый код post и результаты здесь и укажите, как быстро это должно выполняться.

Тогда люди смогут помочь.

Комментарии:

1. Согласен, я не заметил, что там также был HashSet … Знаете, когда вы пришли с языка сценариев (autoit), вы не можете ожидать, что будете знать все. Спасибо за предложение. Пока.

Ответ №2:

Я не уверен, почему использование maps поможет вам сравнить списки строк, но в любом случае:

Если вы не возражаете против использования изменяемой коллекции и уверены, что в вашем списке нет повторов (так что вы действительно можете использовать set), то вы можете использовать MultiMap признак:

 import scala.collection.mutable._
val mm = new HashMap[Char,Set[String]] with MultiMap[Char,String]
Seq("alone","away").foreach(s => mm.addBinding(s(0),s))

scala> mm
res2: scala.collection.mutable.HashMap[Char,scala.collection.mutable.Set[String]]
 with scala.collection.mutable.MultiMap[Char,String] = 
 Map(a -> Set(alone, away))

scala> mm.entryExists('a',"alone")
  

К сожалению, многозадачность исчезает, когда вы используете операцию сбора данных (тогда это просто простая карта от Char до Set[String] ).

Комментарии:

1. Я хотел решить (‘a’, «alone») часть… Я хочу сделать что-то как mm.contains («alone»), и это автоматически сделает что-то как mm ( «alone».charAt(0)).contains( «alone»)…

2. @DDB — Если вам на самом деле никогда не нужен 'a' сам по себе, я думаю, это явный признак того, что вы не применяете правильный подход к решению вашей проблемы. Кроме того, не забывайте, что вы можете просто def has(m: Map[Char,List[String]], s: String) = if (s.length>0) m.get(s.charAt(0)).map(_ contains s).getOrElse(false) else false использовать это вместо того, чтобы каждый раз вводить весь беспорядок.

3. Возможно, я мог бы решить проблему, используя неявное определение… Я не думал об этом таким образом…

4. @DDB — Вы могли бы использовать неявные преобразования, если хотите, чтобы синтаксис m имел «яблоки» вместо has(m, «apples»). В противном случае последнее более эффективно.