2011-09-30 110 views
9

我有一個Hashmap,它可以在字符串中包含通配符(*)。從java中的HashMap返回通配符匹配列表

例如,

HashMap<String, Student> students_; 

可以有約翰·作爲一個重點。我想知道JohnSmith是否與students_中的任何元素相匹配。可能有幾個匹配我的字符串(約翰*,喬*史密斯等)。有什麼辦法可以從我的HashMap中獲得這些匹配的列表嗎?

有沒有另一個對象,我可以使用它不需要我迭代我的集合中的每個元素,還是我必須吸取它並使用List對象?僅供參考,我的收藏將包含少於200個元素,並且最終我會希望找到與最少量通配符匹配的元素組。

+2

哈希函數的方式構建了細微的變化(如:'約翰SmitH'爲' John Smith)產生完全不同的哈希。 – NullUserException

+0

爲什麼你不想迭代?這並不是那麼糟糕(特別是少於200個元素),並且最終任何其他解決方案都可能涉及性能方面的類似情況。 – Guillaume

+0

在少於200個元素的情況下,只需對'entrySet()'進行線性搜索並評估每個鍵的通配符。如果它會更多,我會建議一個(嵌入式)數據庫和一個LIKE查詢。 –

回答

1

由於散列函數,使用hasmap無法實現。它將不得不分配散列"John*"和散列"John Smith"等。相同的價值。

你可以用一個TreeMap做到,如果你編寫自己的自定義類WildcardString包裝帶,並以這樣的方式"John*".compareTo("John Smith")返回0。你可以用正則表達式做到這一點像other answers已經指出的那樣實現compareTo

看到你想要的widlcard匹配列表你可以隨時刪除條目,因爲你找到它們,並迭代TreeMap.get()的。記住一旦完成了名字就把鑰匙放回去。

這只是實現它的一種可能方式。如果少於200個元素,你會很好地迭代。

UPDATE:要在TreeSet正確地維持秩序,您可以分化比較兩個WildcardString S的情況下(這意味着它的鍵之間的比較 - ),並比較WildcardStringString(比較關鍵與搜索值) 。

+0

謝謝哈維。對於200個列表,你認爲使用TreeSet會有什麼性能好處? – Sarah

+2

在WildCardString類中創建compareTo(string)方法會破壞compareTo方法的契約,因爲:'wildCardString.compareTo(string)'可能不是相反的符號或'string.compareTo(wildCardString)'。此外,建議compareTo與等號一致。 – Jim

+0

@jim謝謝你的洞察力,好點。 –

3

您可以使用正則表達式匹配,但您必須先將"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()); 
    } 
} 
+1

他明確表示,他不想迭代所有的條目... – Guillaume

+0

@Guillaume他沒有專門做**不**說。具體來說,他說:*是否有另一個對象我可以使用,不需要我遍歷集合中的每個元素,或者我必須吸取它並使用List對象**?*。我通過確認* OR *部分回答了這個問題。 – Bohemian

+1

波希米亞人,你的詭辯:-)無論如何,我同意你的答案。我不明白他爲什麼不想迭代。 – Guillaume

0

您只需重複您的地圖而不將其轉換成一個列表,並使用字符串匹配功能,王氏使用正則表達式。

如果你想避免循環,你可以使用番石榴這樣

@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")); 

}一般