从java中的HashMap返回通配符匹配列表

Posted

技术标签:

【中文标题】从java中的HashMap返回通配符匹配列表【英文标题】:Returning a list of wildcard matches from a HashMap in java 【发布时间】:2011-11-28 11:15:22 【问题描述】:

我有一个可能在字符串中包含通配符 (*) 的 Hashmap。

例如,

HashMap<String, Student> students_;

可以将 John* 作为一个键。我想知道 JohnSmith 是否匹配 students_ 中的任何元素。我的字符串可能有多个匹配项(John*、Jo*Smith 等)。有什么方法可以从我的 HashMap 中获取这些匹配项的列表?

是否有另一个我可以使用的对象不需要我遍历集合中的每个元素,还是我必须把它吸起来并使用 List 对象?

仅供参考,我的集合中的元素将少于 200 个,最终我会想找到与通配符数量最少匹配的对。

【问题讨论】:

散列函数的构造方式通常是微小的变化(例如:John SmitHJohn Smith)产生完全不同的散列。 为什么不想迭代?这还不错(尤其是少于 200 个元素的情况),最终任何其他解决方案都可能在性能方面涉及类似的东西。 在少于 200 个元素的情况下,只需对 entrySet() 进行线性搜索,然后根据每个键评估通配符。如果它会更多,我建议使用(嵌入式)数据库和LIKE 查询。 谢谢你们。这个列表并不大,但我可能不得不经常做。我很好奇是否有更有效的方法来做到这一点,但也许没有 Partial search in HashMap的可能重复 【参考方案1】:

由于散列函数,不可能使用 hasmap 来实现。它必须分配"John*" 的散列和"John Smith" 等的散列。相同的值。

如果您编写自己的自定义类 WildcardString 包装字符串,并以 "John*".compareTo("John Smith") 返回 0 的方式实现 compareTo,则可以使用 TreeMap 来实现。您可以使用像 @987654321 这样的正则表达式来做到这一点@已经指出了。

看到您想要 widlcard 匹配列表,您总是可以在找到条目时删除它们,然后迭代 TreeMap.get()'s。记得在输入完名字后把钥匙放回去。

这只是实现它的一种可能方式。少于 200 个元素就可以进行迭代。

更新:要对TreeSet 正确施加顺序,您可以区分比较两个WildcardStrings(意味着它是键之间的比较)和比较WildcardString 和a String(将键与搜索值进行比较)。

【讨论】:

谢谢你,哈维。对于 200 个列表,您认为使用 TreeSet 会有什么性能优势吗? 在 WildCardString 类中创建 compareTo(string) 方法会破坏 compareTo 方法的约定,因为:wildCardString.compareTo(string) 可能不是相反的符号或 string.compareTo(wildCardString)。另外建议 compareTo 与 equals 一致。【参考方案2】:

您可以使用正则表达式进行匹配,但您必须先将 "John*" 转换为等效的正则表达式 "John.*",尽管您可以即时执行此操作。

下面是一些可以工作的代码:

String name = "John Smith"; // For example
Map<String, Student> students_ = new HashMap<String, Sandbox.Student>();

for (Map.Entry<String, Student> entry : students_.entrySet()) 
    // If the entry key is "John*", this code will match if name = "John Smith"
    if (name.matches("^.*" + entry.getKey().replace("*", ".*") + ".*$")) 
        // do something with the matching map entry
        System.out.println("Student " + entry.getValue() + " matched " + entry.getKey());
    

【讨论】:

@Guillaume 不,他确实这么说。具体来说,他说:是否有另一个我可以使用的对象不需要我遍历我的集合中的每个元素,或者我必须把它吸起来并使用一个 List 对象 ?.我通过确认 OR 部分回答了这个问题。 波西米亚人,你这个诡辩家 :-) 我同意你的回答。我不明白他为什么不想迭代。【参考方案3】:

您可以只迭代您的地图而不将其转换为列表,并使用字符串匹配函数,使用正则表达式。

如果你想避免循环,你可以像这样使用番石榴

@Test
public void hashsetContainsWithWildcards() throws Exception 
Set<String> students = new HashSet<String>();
students.add("John*");
students.add("Jo*Smith");
students.add("Bill");

Set<String> filteredStudents = Sets.filter(students, new Predicate<String>() 
  public boolean apply(String string) 
    return "JohnSmith".matches(string.replace("*", ".*"));
  
);

assertEquals(2, filteredStudents.size());
assertTrue(filteredStudents.contains("John*"));
assertTrue(filteredStudents.contains("Jo*Smith"));

【讨论】:

以上是关于从java中的HashMap返回通配符匹配列表的主要内容,如果未能解决你的问题,请参考以下文章

Java PreparedStatements 中的通配符

Linux文件通配符

Python Pandas Regex:在列中搜索带有通配符的字符串并返回匹配项[重复]

linux通配符

LeetCode--044--通配符匹配(java)*

如何在 Java 中查找与通配符字符串匹配的文件?