2011-09-30 31 views
9

Tôi có Hashmap có thể chứa ký tự đại diện (*) trong chuỗi.Trả về danh sách các đối sánh ký tự đại diện từ HashMap trong java

Ví dụ,

HashMap<String, Student> students_; 

thể có John * như một chìa khóa. Tôi muốn biết liệu JohnSmith có phù hợp với bất kỳ yếu tố nào trong học sinh không. Có thể có nhiều kết quả phù hợp cho chuỗi của tôi (John *, Jo * Smith, v.v.). Có cách nào tôi có thể nhận được một danh sách các trận đấu từ HashMap của tôi?

Có đối tượng nào khác mà tôi có thể sử dụng không yêu cầu tôi lặp qua mọi phần tử trong bộ sưu tập của mình hay tôi phải hút nó lên và sử dụng đối tượng Danh sách?

FYI, bộ sưu tập của tôi sẽ có ít hơn 200 phần tử trong đó và cuối cùng tôi sẽ muốn tìm cặp phù hợp với số lượng ký tự đại diện ít nhất.

+2

chức năng Băm nói chung được xây dựng trong một cách mà những thay đổi nhỏ (ví dụ: 'John SmitH' cho' John Smith') tạo ra các băm hoàn toàn khác nhau. – NullUserException

+0

Tại sao bạn không muốn lặp lại? Nó không phải là xấu (đặc biệt là với ít hơn 200 yếu tố), và cuối cùng bất kỳ giải pháp khác sẽ có khả năng liên quan đến một cái gì đó tương tự về hiệu suất. – Guillaume

+0

Tại ít hơn 200 phần tử, chỉ cần thực hiện tìm kiếm tuyến tính trên 'entrySet()' và đánh giá ký tự đại diện của bạn dựa trên mỗi khóa.Nếu nó đã được nhiều hơn nữa, tôi đã đề nghị một cơ sở dữ liệu (nhúng) và một truy vấn 'LIKE'. –

Trả lời

1

Không thể đạt được với một bản đồ, vì chức năng băm. Nó sẽ phải gán giá trị băm của "John*" và giá trị băm của "John Smith" et al. cùng một giá trị.

Bạn có thể làm cho nó với một TreeMap, nếu bạn viết riêng lớp tùy chỉnh WildcardString gói Chuỗi của bạn, và thực hiện compareTo theo cách như vậy mà "John*".compareTo("John Smith") trả về 0. Bạn có thể làm điều này với biểu thức thông thường như other answers đã chỉ ra.

Thấy rằng bạn muốn danh sách các đối sánh widlcard bạn luôn có thể xóa các mục nhập khi tìm thấy chúng và lặp lại TreeMap.get(). Hãy nhớ đặt các phím trở lại sau khi hoàn thành với một tên.

Đây chỉ là một cách có thể để đạt được điều đó. Với ít hơn 200 yếu tố bạn sẽ được lặp lại tốt.

UPDATE: Để áp đặt trật tự một cách chính xác trên TreeSet, bạn có thể phân biệt các trường hợp so sánh hai WildcardString s (có nghĩa là đó là một comparation giữa các phím) và so sánh một WildcardString đến một String (so sánh một chìa khóa với một giá trị tìm kiếm) .

+0

Cảm ơn bạn, Xavi. Đối với một danh sách 200 bạn có nghĩ rằng sẽ có bất kỳ lợi ích hiệu suất để sử dụng một TreeSet? – Sarah

+2

Tạo phương thức compareTo (chuỗi) trong lớp WildCardString sẽ phá vỡ hợp đồng của phương thức compareTo vì: 'wildCardString.compareTo (chuỗi)' có thể không phải là dấu đối diện hoặc 'string.compareTo (wildCardString)'. Ngoài ra, nó được khuyến nghị là compareTo là nhất quán với equals. – Jim

+0

@jim Cảm ơn sự hiểu biết của bạn, điểm tốt. –

3

Bạn có thể sử dụng regex để khớp, nhưng trước tiên bạn phải chuyển "John*" thành số tương đương regex "John.*", mặc dù bạn có thể thực hiện điều đó một cách nhanh chóng.

Dưới đây là một số mã mà sẽ làm việc:

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

Ông đặc biệt nói rằng ông không muốn lặp lại tất cả các mục ... – Guillaume

+0

@Guillaume không có ông cụ thể đã làm ** KHÔNG ** nói điều đó. Cụ thể, ông nói: * Có một đối tượng khác mà tôi có thể sử dụng không yêu cầu tôi lặp qua mọi phần tử trong bộ sưu tập của mình, hay tôi phải hút nó lên và sử dụng đối tượng List **? *. Tôi đã trả lời câu hỏi bằng cách xác nhận phần * HOẶC *. – Bohemian

+1

Bohemian, bạn là người tiên phong :-) Tôi đồng ý với câu trả lời của bạn. Tôi không hiểu tại sao anh ta không muốn lặp lại. – Guillaume

0

Bạn chỉ có thể lặp Bản đồ của bạn mà không cần chuyển đổi nó thành một danh sách, và sử dụng các chuỗi phù hợp với chức năng, wih sử dụng một regexp.

Nếu bạn muốn tránh các vòng lặp, bạn có thể sử dụng ổi như thế này

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

}

Các vấn đề liên quan