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
This calls for a Trie data structure. See this question for java implementations. I used this one.
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
).
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.
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()));
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+"]";
}
}