Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HashMap中的部分搜索_Java_Map_Filtering - Fatal编程技术网

Java HashMap中的部分搜索

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

我需要创建电话簿之类的东西。它包含名称和编号。现在,当我键入字母时,匹配列表应返回。对于下面给出的示例,当我键入H时,应返回包含Harmer、Harris、Hawken和Hosler的列表。当输入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");
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()));