2016-11-04 25 views
8

Làm cách nào để tính toán giá trị trung bình có trọng số là Map<Double, Integer> trong đó giá trị Số nguyên là trọng số cho giá trị kép được tính trung bình. ví dụ như: các yếu tố đồ đã sau:Tính trung bình có trọng số với các luồng Java 8

  1. (0,7, 100) // giá trị là 0,7 và trọng lượng là 100
  2. (0,5, 200)
  3. (0,3, 300)
  4. (0,0, 400)

Tôi đang tìm cách áp dụng công thức sau đây bằng cách sử dụng luồng Java 8, nhưng không chắc cách tính toán tử số và mẫu số với nhau và bảo toàn nó cùng một lúc. Làm thế nào để sử dụng giảm ở đây?

enter image description here

+3

Bạn đã kiểm tra ['Collectors.averagingDouble'] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#averagingDouble-java.util.function .ToDoubleFunction-) phương pháp? – Aaron

Trả lời

9

Bạn có thể tạo thu của riêng bạn cho nhiệm vụ này:

static <T> Collector<T,?,Double> averagingWeighted(ToDoubleFunction<T> valueFunction, ToIntFunction<T> weightFunction) { 
    class Box { 
     double num = 0; 
     long denom = 0; 
    } 
    return Collector.of(
      Box::new, 
      (b, e) -> { 
       b.num += valueFunction.applyAsDouble(e) * weightFunction.applyAsInt(e); 
       b.denom += weightFunction.applyAsInt(e); 
      }, 
      (b1, b2) -> { b1.num += b2.num; b1.denom += b2.denom; return b1; }, 
      b -> b.num/b.denom 
      ); 
} 

sưu tập tùy chỉnh này có hai chức năng như tham số: một là một hàm trả về giá trị sử dụng cho một yếu tố dòng nhất định (dưới dạng ToDoubleFunction) và phương thức kia trả về trọng số (dưới dạng ToIntFunction). Nó sử dụng một lớp địa phương trợ giúp để lưu trữ tử số và mẫu số trong quá trình thu thập. Mỗi lần một mục được chấp nhận, tử số được tăng lên với kết quả nhân giá trị với trọng số của nó, và mẫu số được tăng lên với trọng số. Người hoàn thành sau đó trả về bộ phận của hai như là Double.

Cách sử dụng mẫu sẽ là:

Map<Double,Integer> map = new HashMap<>(); 
map.put(0.7, 100); 
map.put(0.5, 200); 

double weightedAverage = 
    map.entrySet().stream().collect(averagingWeighted(Map.Entry::getKey, Map.Entry::getValue)); 
+0

Cảm ơn lời giải thích tuyệt vời này. Tôi sẽ đọc thêm về các nhà sưu tập tùy chỉnh. –

0

Bạn có thể sử dụng phương pháp này để tính bình quân gia quyền của bản đồ. Lưu ý rằng khóa của mục nhập bản đồ phải chứa giá trị và giá trị của mục nhập bản đồ phải chứa trọng số.

 /** 
    * Calculates the weighted average of a map. 
    * 
    * @throws ArithmeticException If divide by zero happens 
    * @param map A map of values and weights 
    * @return The weighted average of the map 
    */ 
    static Double calculateWeightedAverage(Map<Double, Integer> map) throws ArithmeticException { 
     double num = 0; 
     double denom = 0; 
     for (Map.Entry<Double, Integer> entry : map.entrySet()) { 
      num += entry.getKey() * entry.getValue(); 
      denom += entry.getValue(); 
     } 

     return num/denom; 
    } 

Bạn có thể xem thử nghiệm đơn vị của nó để xem lượt sử dụng.

 /** 
    * Tests our method to calculate the weighted average. 
    */ 
    @Test 
    public void testAveragingWeighted() { 
     Map<Double, Integer> map = new HashMap<>(); 
     map.put(0.7, 100); 
     map.put(0.5, 200); 
     Double weightedAverage = calculateWeightedAverage(map); 
     Assert.assertTrue(weightedAverage.equals(0.5666666666666667)); 
    } 

Bạn cần những hàng nhập khẩu đối với các bài kiểm tra đơn vị:

import org.junit.Assert; 
import org.junit.Test; 

Bạn cần những hàng nhập khẩu đối với các mã:

import java.util.HashMap; 
import java.util.Map; 

Tôi hy vọng nó giúp.

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