2012-06-22 28 views
6

Tôi có mộtJava Bản đồ, bộ lọc với các giá trị thuộc tính

TreeMap resMap new TreeMap<String, Map<String, String>>(); 

Tôi muốn lọc và giữ chỉ mục mà giá trị có chứa một cặp nổi tiếng, giả sử ('mike' => 'jordan'), và tránh một vòng lặp như dưới đây

có trong thư viện apache.commons bao gồm tôi và google.common một phương pháp lọc (mà có lẽ sẽ làm một vòng lặp quá, nhưng ít nhất nó ít tiết

for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){ 
    if (el.getValue().get("mike").equals("jordan")){ 
     // 
    } 
} 
+0

Bạn cần một số loại LINQ tương đương DotNet trong Java ... – Wins

+2

Tại sao bạn muốn tránh một vòng lặp? Bất cứ điều gì bạn sử dụng cũng giống như sử dụng vòng lặp cho bạn. –

+3

Nhận xét nhỏ: chuyển đổi thứ tự trong bằng, vì get ("mike") có thể trả về giá trị rỗng. tức là 'if (" jordan ".equals (el.getValue(). get (" mike "))' – user949300

Trả lời

9

Bạn có thể sử dụng bộ lọc từ ổi và giao diện Predicate.

Predicate<T> yourFilter = new Predicate<T>() { 
    public boolean apply(T o) { 
     // your filter 
    } 
}; 

Vì vậy, ví dụ đơn giản sẽ là:

Predicate<Integer> evenFilter = new Predicate<Integer>() { 
    public boolean apply(Integer i) { 
     return (i % 2 == 0); 
    } 
}; 

Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 

Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter); 
+0

Tôi nghĩ, mặc dù bộ lọc ổi có cùng khoảng thời gian cho dù bản đồ lớn hơn hay nhỏ hơn, nhưng việc sử dụng lặp lại cho các bản đồ có kích thước nhỏ sẽ cho hiệu suất tốt hơn. –

0

Hãy xem tại Guava 's PredicatesFunctions.

+0

Các vòng lặp sử dụng này. –

+3

Đương nhiên! Họ cũng loại bỏ trùng lặp các vòng lặp đó từ mã của người dùng. –

+1

Và thay thế chúng bằng các biến vị ngữ có thể dài hơn các vòng lặp mà chúng thay thế. ;) –

4

Thay vì buộc mã khách hàng của bạn sử dụng một bộ lọc/vòng lặp, xây dựng những gì bạn cần vào API của lớp học của bạn:

public class MyClass { 

    private TreeMap resMap new TreeMap<String, Map<String, String>>(); 

    public void filter(String key, String value) { 
     // Some impl here. Either your loop or the guava approach 
    } 
} 

BTW, nếu bạn sử dụng vòng lặp của mình, hãy xem xét việc thay đổi điều này:

for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) { 
    Map.Entry<String, TreeMap<String, String>> entry = i.next(); 
    if (value.equals(entry.getValue().get(key))) { 
     i.remove(); 
    } 
} 

Những thay đổi vòng lặp là:

  • trật tự đã thay đổi của bình đẳng để tránh NPE
  • Sử dụng iterator để cho phép loại bỏ các mục trực tiếp

Thậm chí nếu bạn không có một lớp, bạn có thể dễ dàng quấn nó lên trong một phương pháp tĩnh trên một lớp tiện ích, nơi nó cũng có thể dễ dàng được tham số hóa để làm việc với bất kỳ bản đồ lồng nhau nào:

public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) { 
    // Some impl here 
} 

Dưới đây là một impl phi ổi đối với phương pháp tĩnh:

for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) { 
    Map.Entry<K1, Map<K2, V>> entry = i.next(); 
    if (value.equals(entry.getValue().get(key))) { 
     i.remove(); 
    } 
} 
+0

Thay vì phát minh lại bánh xe, hãy sử dụng các khung công tác hiện có. –

+1

@EugeneKuleshov Tốt, nhưng đó là một lựa chọn thực hiện. Lực đẩy chính của câu trả lời này là cung cấp một API để mã khách hàng không cần biết về ổi/vòng lặp vv. Tôi đã chỉnh sửa câu trả lời để nói điều này. – Bohemian

+0

@EugeneKuleshov Thay vì phát minh lại vòng lặp, chỉ cần sử dụng vòng lặp là cấu trúc ngôn ngữ. ;) –

0

Dưới đây là hai ví dụ. Cả hai đều in khóa dựa trên đối sánh trong thuộc tính của giá trị.

private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) { 
    for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet()) 
     if (value.equals(entry.getValue().get(key))) 
      System.out.println(entry.getKey()); 
} 

private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) { 
    Predicate<Map<String, String>> keyValueMatch = 
    new Predicate<Map<String, String>>() { 
     @Override 
     public boolean apply(@Nullable Map<String, String> stringStringMap) { 
      return value.equals(stringStringMap.get(key)); 
     } 
    }; 

    Maps.EntryTransformer<String, Map<String, String>, Void> printKeys = 
    new Maps.EntryTransformer<String, Map<String, String>, Void>() { 
     @Override 
     public Void transformEntry(@Nullable String s, 
       @Nullable Map<String, String> stringStringMap) { 
      System.out.println(s); 
      return null; 
     } 
    }; 

    Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys); 
} 

public static void main(String... args) { 
    Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>(); 
    printMatchingEntriesUsingALoop(resMap, "first", "mike"); 
    printMatchingEntriesUsingGuava(resMap, "first", "mike"); 
} 

Một sử dụng vòng lặp và một lần sử dụng Ổi.

Trong khi phiên bản đầu tiên hoạt động tốt hơn, bạn nên thực sự quyết định cái nào sẽ dễ hiểu và dễ bảo trì nhất.

Một số đề xuất từ ​​@missingfaktor. Bạn phải sử dụng bản án của riêng bạn, nhưng ông đã nêu bật một số vấn đề tốt.

  1. nhiều lần sao chép mã.
  2. xử lý trường hợp đặc biệt.
  3. Độ phức tạp của chu trình khác.
  4. Nhiều cơ hội lỗi hơn, do kết quả của ba dấu đầu tiên.
  5. Khó theo dõi mã.

Hãy tưởng tượng bạn là nhà phát triển mới, những người phải hỗ trợ phần mềm này. Mà bạn muốn được đối mặt?

0

Bạn có thể lọc bản đồ bằng cách sử dụng java 8 và suối. Bước đầu tiên trong quá trình này là chuyển đổi sang luồng bằng cách sử dụng entrySet().stream(). Điều này cung cấp cho bạn một số Stream<Map.Entry<String, TreeMap<String, String>>. Sau đó, bạn có thể sử dụng filter(...) để lọc danh sách. Khi bạn lọc, bạn nên trả về true khi giá trị đến phải được bao gồm trong kết quả bộ lọc. Sau khi bạn lọc kết quả, bạn có thể sử dụng foreach để lặp qua kết quả cuối cùng.

Kết quả cuối cùng sẽ trông giống như sau:

resMap.entrySet().stream() 
     .filter(e -> el.getValue().get("mike").equals("jordan")) 
     .foreach(e -> { 
     // Do something with your entry here 
     }); 
Các vấn đề liên quan