Java HashMap中的部分搜索
我需要创建电话簿之类的东西。它包含名称和编号。现在,当我键入字母时,匹配列表应返回。对于下面给出的示例,当我键入H时,应返回包含Harmer、Harris、Hawken和Hosler的列表。当输入Ha时,应返回仅包含Harmer、Harris和Hawken的列表Java HashMap中的部分搜索,java,map,filtering,Java,Map,Filtering,我需要创建电话簿之类的东西。它包含名称和编号。现在,当我键入字母时,匹配列表应返回。对于下面给出的示例,当我键入H时,应返回包含Harmer、Harris、Hawken和Hosler的列表。当输入Ha时,应返回仅包含Harmer、Harris和Hawken的列表 Map<String, String> nameNum = new HashMap<String, String>(); nameNum.put("Brown", "+1236389023"); n
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");
Map nameNum=newhashmap();
nameNum.put(棕色,“+1236389023”);
nameNum.put(“Bob”、“+1236389023”);
nameNum.put(“哈默”、“+1236389023”);
nameNum.put(“哈里斯”、“+1236389023”);
nameNum.put(“霍肯”,“1236389023”);
nameNum.put(“Hosler”、“+1236389023”);
你知道怎么做到吗?
提前谢谢 这需要一个数据结构。有关java实现,请参阅。我使用了。将其全部放在一个多重映射中(或者只在HashMap中存储一个列表作为值)。对于“棕色”,商店:
如果以后添加“布拉德利”:
等等
然后使用另一个映射将“布朗”或“布拉德利”映射到电话号码。是的,哈希映射不是用于此目的的正确数据结构。正如波佐所说,a将是正确的选择 使用Java的板载工具,可以使用TreeMap(实际上是任何树映射):
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;
}
public SortedMap filterPrefix(SortedMap底图,字符串前缀){
if(前缀.length()>0){
char nextLetter=prefix.charAt(prefix.length()-1)+1;
字符串结束=prefix.substring(0,prefix.length()-1)+nextLetter;
返回baseMap.subMap(前缀,结束);
}
返回底图;
}
输出甚至可以按键排序
下面是一个使用示例:
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);
}
SortedMap nameNum=newtreemap();
//记下你的电话号码
字符串前缀=。。。;
for(Map.Entry:filterPrefix(nameNum,prefix).entrySet()){
系统输出打印项次(输入);
}
如果希望前缀过滤器不依赖于大小写差异,请为地图使用合适的比较器(如具有合适强度设置的拼贴器
,或字符串。不区分大小写\u顺序
)。使用将简化解决方案
密钥是姓名的第一个字母,该值是一个集合
,包含所有姓名以密钥(第一个字母)开头的姓名电话对
例如:
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+"]";
}
公共无效测试(){
//firstLetter->姓名电话对列表
Multimap mMap=ArrayListMultimap.create();
看跌期权(mMap,棕色,“+1236389023”);
put(mMap,“Bob”,“+1236389023”);
put(mMap,“Harmer”、“+1236389023”);
看跌期权(mMap,Harris,“+1236389023”);
put(mMap,霍肯,“+1236389023”);
put(mMap,Hosler,“+1236389023”);
//试验
System.out.println(mMap.get(“H”);
}
void put(多重映射mMap、字符串名称、字符串电话){
mMap.put(name.substring(0,1),新对(name,phone));
}
公共静态类对{
字符串名;
字符串电话;
公用对(字符串名称、字符串电话){
this.name=名称;
this.phone=电话;
}
@凌驾
公共字符串toString(){
返回“Pair[name=“+name+”,phone=“+phone+”]”;
}
}删除所有不包含关键部分的值:
yourMap.keySet().removeIf(key -> !key.contains(keyPart));
或正则表达式:
yourMap.keySet().removeIf(key -> !key.matches(".*keyPart.*"));
或过滤流并收集到新地图:
yourMap.entrySet().stream().filter(e -> e.getKey().contains(keyPart)).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
您确定使用
HashMap
是这样一个好主意吗?我认为不同的数据结构可能更好。您是只查找第一个字母,还是在键入时删除了列表?例如,输入“Ha”是否会消除“Hosler”?从该数据结构中添加和删除内容将非常昂贵。我同意。但我们甚至不知道他的“电话簿”有多大。我更喜欢先做一些简单的事情,然后再优化。这似乎是最简单的事情,访问应该是O(1),而对于树,访问应该是log(n)。如果你在做像自动完成这样的事情,这不是更重要吗?数据集多久更新一次?如果GET设置的频率要高得多,谁会在乎添加/删除的速度有多慢。在这里添加和删除也没那么糟糕,我不认为。谢谢Bozho,你的链接很有用!但这一问题得到回答已经快三年了。现在有没有更好的解决方案,您可能已经注意到了?链接再次中断Bozho@Pa卢埃伯曼:为什么是Trie,它如何节省空间{}?你也可以使用前缀+“\uffff”作为结尾。@PaŭloEbermann我有同样的场景。但是现有的映射是一个HashMap实现(针对10k+元素),不能更改。现在,为了按照上面的解决方案实现这一点,如果我将Hashmap中包含的全部内容转储到TreeMap中,TreeMap本身的构建将非常昂贵(因为它构建了一个排序结构),其余的可能会简单而快速。有没有关于根据我的要求包装此解决方案的建议?@abksrv如果这只是一次搜索,那么对HashMap的所有条目进行一次迭代应该是最快的。如果您想更频繁地执行此操作,请将数据传输到更好的结构中。(另外,测量:可能对于您的数据集和硬件,甚至不需要优化。)
yourMap.keySet().removeIf(key -> !key.matches(".*keyPart.*"));
yourMap.entrySet().stream().filter(e -> e.getKey().contains(keyPart)).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));