2014-10-12 36 views
6

Tôi có một bản đồ Map<String, List<Double> và tôi muốn tìm giá trị tối đa (hoặc tối thiểu) trong tất cả các danh sách. Hàm sẽ trả về giá trị lớn nhất (hoặc nhỏ nhất) và khóa thuộc về giá trị đó.Java 8 Hash Map

Chữ ký có thể

public static Pair<String,Double> getKeyValue(Map<String, List<Double>> map, BinaryOperator<Double> function)

mà được bản đồ và chức năng Double::max hoặc Double::min

Làm thế nào tôi có thể thực hiện điều này một cách hiệu quả (và đẹp) sử dụng java 8, suối api?

Trả lời

4

A BinaryOperator không phải là một đặc điểm kỹ thuật tốt cho nhiệm vụ đó, nó là thẳng về phía trước để sử dụng trong một giảm để tạo ra giá trị thích hợp, ví dụ: tối thiểu hoặc tối đa, tuy nhiên nó không thích hợp để trả về một giá trị liên quan như giá trị khóa của Map. Sử dụng nó theo cách này ngụ ý rằng việc thực hiện phải thực hiện các hoạt động bổ sung để tìm hiểu, những gì BinaryOperator thực sự đã làm để chọn giá trị khóa chính xác trong quá trình giảm. Thậm chí tệ hơn, nó không thể bảo đảm rằng BinaryOperator thực hiện điều gì đó cho phép thực hiện loại giảm này, ví dụ: toán tử có thể trả về một giá trị không phải là đối số của nó.

Đối với tác vụ như vậy, Comparator là lựa chọn tốt hơn vì nó được thiết kế để chỉ định một đơn hàng và thực hiện các hoạt động liên quan như tìm tối đa và tối thiểu. An thực hiện có thể trông như thế này:

public static Pair<String,Double> getMinimumKeyValue(
    Map<String, List<Double>> map, Comparator<Double> function) { 

    return map.entrySet().stream() 
     .map(e->new Pair<>(e.getKey(), e.getValue().stream().min(function).get())) 
     .min(Comparator.comparing(Pair::getRight, function)).get(); 
} 

Nó được đặt tên getMinimumKeyValue vì nó sẽ trở lại với cặp khóa/giá trị tối thiểu khi bạn vượt qua trong Comparator.naturalOrder().

Nhưng bạn cũng có thể nhận tối đa bằng cách đi qua Comparator.reverseOrder().

Và thật dễ dàng để sửa đổi để hỗ trợ một phạm vi rộng hơn về trường hợp sử dụng:

public static <K,V> Pair<K,V> getMinKeyValue(
    Map<K, ? extends Collection<V>> map, Comparator<? super V> function) { 

    return map.entrySet().stream() 
     .map(e->new Pair<>(e.getKey(), e.getValue().stream().min(function).get())) 
     .min(Comparator.comparing(Pair::getRight, function)).get(); 
} 

này vẫn hoạt động để có được một Pair<String,Double> ra khỏi một Map<String, List<Double>> nhưng có thể làm nhiều hơn ...

4

Bạn có thể thử này:

public static Pair<String,Double> getKeyValue(Map<String,List<Double>> map, 
     BinaryOperator<Double> function) { 
     return map.entrySet().stream() 
      .map(e -> new Pair<String,Double>(e.getKey(),e.getValue().stream().reduce(function).get())) 
      .reduce((p1,p2) -> function.apply(p1.getValue(),p2.getValue()).equals(p1.getValue()) ? p1 : p2) 
      .get(); 
} 

Giải thích:

Trước tiên, bạn kết hợp mỗi Entry<String,List<Double>> đến một Pair<String,Double> trong đó giá trị là min (hoặc tối đa) của danh sách và phần còn lại chủ chốt tương tự, sau đó bạn so sánh từng số Pair<String,Double> để tìm giá trị có giá trị thấp nhất (hoặc cao nhất).

+2

Bạn đang sử dụng '==' đóng hộp 'Double', dường như không hoạt động như mong đợi. Tôi có xu hướng cố gắng di chuyển ra khỏi phương pháp 'BinaryOperator ' và thích 'Comparator' .... –

+0

Đúng vậy, nhưng tôi sẽ thay đổi thử nghiệm thành' a.equals (b) 'để sửa nó . Cảm ơn vì đã chú ý điều đó! – Dici

+0

Tôi thực sự không thể đọc được điều này. Có lẽ đó là cú pháp, các cặp chữ bị thiếu, dù sao đi nữa, nhưng tôi có ít vấn đề hơn khi đọc Haskell. Nói chung, cách tiếp cận chức năng thường ít có thể đọc được nhiều hơn so với kiểu cũ đơn giản trong Java. –