Partial search in HashMap

前端 未结 5 752
后悔当初
后悔当初 2020-11-29 03:55

I need to create phone book kind of thing. It contains name & number. Now when I type letters matching list should be returned. For the example given below, when I type

相关标签:
5条回答
  • 2020-11-29 04:35

    This calls for a Trie data structure. See this question for java implementations. I used this one.

    0 讨论(0)
  • 2020-11-29 04:40

    Yeah, a HashMap is not the right data structure for this. As Bozho said, a Trie would be the right one.

    With Java's on-board tools, a TreeMap (or any SortedMap, actually) could be used:

    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;
    }
    

    The output would even be sorted by key.

    Here an usage example:

    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);
    }
    

    If you want your prefix filter to not be depending on case differences, use a suitable Comparator for your map (like a Collator with a suitable strength setting, or String.CASE_INSENSITIVE_ORDER).

    0 讨论(0)
  • 2020-11-29 04:41

    Put it all in a MultiMap (or just store a List as the value in your HashMap). For "Brown", store:

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

    If you later add "Bradley":

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

    etc...

    then have another map to map "Brown" or "Bradley" to the phone number.

    0 讨论(0)
  • 2020-11-29 04:44

    Remove all values which doesn't contain key part:

    yourMap.keySet().removeIf(key -> !key.contains(keyPart));
    

    Or regex:

    yourMap.keySet().removeIf(key -> !key.matches(".*keyPart.*"));
    

    Or filter stream and collect to a new map:

    yourMap.entrySet().stream().filter(e -> e.getKey().contains(keyPart)).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
    
    0 讨论(0)
  • 2020-11-29 04:47

    Use guava Multimap will ease your solution.

    The key is first letter of name, the value is a Collection containing all name-phone pair which name is started with the key(first letter).

    Example:

        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+"]";
          }
    

    }

    0 讨论(0)
提交回复
热议问题