Подтвердить что ты не робот

Частичный поиск в HashMap

Мне нужно создать телефонную книгу. Он содержит имя и номер. Теперь, когда я набираю буквы, соответствующий список должен быть возвращен. В приведенном ниже примере, когда я печатаю H, список, содержащий Хармер, Харрис, Хокен, Хослер, должен быть возвращен. Когда тип Ha, тогда список, содержащий только Harmer, Harris, Hawken должен быть возвращен.

  Map<String, String> nameNum = new HashMap<String, String>();

  nameNum.put("Brown", "+1236389023");
  nameNum.put("Bob", "+1236389023");
  nameNum.put("Harmer", "+1236389023");
  nameNum.put("Harris", "+1236389023");
  nameNum.put("Hawken", "+1236389023");
  nameNum.put("Hosler", "+1236389023");

Любая идея, как это достичь? Заранее спасибо.

4b9b3361

Ответ 1

Да, HashMap не является подходящей структурой данных для этого. Как сказал Божо, Trie будет правильным.

С встроенными инструментами Java на самом деле можно использовать TreeMap (или любой SortedMap):

public <V> SortedMap<String, V> filterPrefix(SortedMap<String,V> baseMap, String prefix) {
    if(prefix.length() > 0) {
        char nextLetter = prefix.charAt(prefix.length() -1) + 1;
        String end = prefix.substring(0, prefix.length()-1) + nextLetter;
        return baseMap.subMap(prefix, end);
    }
    return baseMap;
}

Выход будет даже отсортирован по ключу.

Вот пример использования:

SortedMap<String, String> nameNum = new TreeMap<String, String>();
// put your phone numbers

String prefix = ...;
for(Map.Entry<String,String> entry : filterPrefix(nameNum, prefix).entrySet()) {
    System.out.println(entry);
}

Если вы хотите, чтобы ваш префиксный фильтр не зависел от различий в регистре, используйте подходящий компаратор для вашей карты (например, Collator с подходящей настройкой силы или String.CASE_INSENSITIVE_ORDER).

Ответ 2

Это вызывает структуру данных Trie. См. этот вопрос для реализации Java. Я использовал этот.

Ответ 3

Поместите все это в MultiMap (или просто сохраните List как значение в вашем HashMap). Для "Брауна" сохраните:

"B"->["Brown"]
"BR"->["Brown"]
"BRO"->["Brown"]

Если вы позже добавите "Bradley":

"B"->["Brown", "Bradley"]
"BR"->["Brown", "Bradley"]
"BRO"->["Brown"]
"BRA"->["Bradley"]

и т.д...

то есть еще одна карта, чтобы нанести на карту "Браун" или "Брэдли" на номер телефона.

Ответ 4

Использовать guava Multimap облегчит ваше решение.

Ключ - это первая буква имени, значение - Collection, содержащее все пары имя-телефон, имя которого начинается с ключа (первая буква).

Пример:

    public void test(){
      //firstLetter -> list of name-phone pair
      Multimap<String, Pair> mMap =  ArrayListMultimap.create();

      put(mMap, "Brown",  "+1236389023");
      put(mMap, "Bob",    "+1236389023");
      put(mMap, "Harmer", "+1236389023");
      put(mMap, "Harris", "+1236389023");
      put(mMap, "Hawken", "+1236389023");
      put(mMap, "Hosler", "+1236389023");

      //Test
      System.out.println(mMap.get("H"));
   }

   void put(Multimap<String, Pair> mMap, String name, String phone){
      mMap.put(name.substring(0,1), new Pair(name, phone));
   }

   public static class Pair{
      String name;
      String phone;

      public Pair(String name, String phone) {
         this.name = name;
         this.phone = phone;
      }

      @Override
      public String toString() {
         return "Pair [name="+name+", phone="+phone+"]";
      }

}