2017-08-16 19 views
1

有一個對象如何使用java8流獲取多屬性的平均值?

@Data 
class ScoreInfo{ 
String id; 

float cove_score; 
float theam_score; 
float content_score; 
float teach_score; 

Date create_date; 
ScoreInfoP scoreInfoP; 

}

和ScoreInfoP是:

@Data 
class ScoreInfoP{ 

String stream_sn; 

String anchor_id; 

String create_by; 
} 

SOURCELIST是ScoreInfo的名單,我想cove_score,theam_score,content_score,teach_score的平均值,組通過scoreInfoP屬性並返回每個屬性的四個平均值。

我可以用這樣的代碼只能得到一個平均值:

Map<ScoreInfoP, Double> meanForCoveScore = sourceList.stream().collect(Collectors.groupingBy(ScoreInfo::getScoreInfoP, 
      Collectors.averagingDouble(ScoreInfo::getCove_score))); 

我想學習怎樣用java8或您建議實現這一目標變得更容易雙向四個平均值。

在此等待您的慷慨幫助。

+0

你的意思是讓每個平均值? –

+0

最優雅的方法是創建一個結果類。 – Flown

+0

@ holi-java是的,我想得到四個平均值 –

回答

3

有沒有什麼集結在此,但它並不複雜,以建立一個定製的珍藏......

Map<String, List<Float>> result = Arrays.asList(first, second) 
      .stream() 
      .collect(Collectors.groupingBy(
        x -> x.getScoreInfoP().getAnchorId(), 
        Collector.of(
          () -> new float[5], 
          (a, x) -> { 
           a[0] += x.getCoveScore(); 
           a[1] += x.getTheamScore(); 
           a[2] += x.getTeachScore(); 
           a[3] += x.getContentScore(); 
           a[4]++; 
          }, 

          (left, right) -> { 
           for (int i = 0; i < 4; ++i) { 
            left[i] += right[i]; 
           } 

           return left; 
          }, x -> Arrays.asList(x[0]/x[4], x[1]/x[4], x[2]/x[4], x[3]/x[4])) 

    )); 

    System.out.println(result); 

我其實GROUPBY這裏ScoreInfoP#anchorId;但你可以在ScoreInfoP上做 - 因爲你需要將x -> x.getScoreInfoP().getAnchorId()更改爲x -> x.getScoreInfoP()。但顯然ScoreInfoP需要覆蓋hashCodeequals

+0

我使用龍捲風,與數據註釋,我不需要提供哈希碼和等於。我用你的模板改變了我的代碼,但它失敗了。但我認爲你清楚的方式是正確的,我需要了解它並找出失敗的原因。 –

+0

現在編譯成功。現在我沒有要測試的數據,我必須等待幾天才能測試代碼。 –

+0

@RickGeng它真的很容易測試,它的工作原理...但嘿你的選擇真的 – Eugene

1

正如我在評論中所說,你應該使用適當的結果類。

class ScoreInfoAverage { 
    private float cove_score; 
    private float theam_score; 
    private float content_score; 
    private float teach_score; 

    // ctor, getter, setter 
} 

然後你就可以使用自定義Collector

public static Collector<ScoreInfo, ?, ScoreInfoAverage> scoreInfoToAverage() { 
    class ScoreInfoAccumulator { 
    private DoubleSummaryStatistics cove_score = new DoubleSummaryStatistics(); 
    private DoubleSummaryStatistics theam_score = new DoubleSummaryStatistics(); 
    private DoubleSummaryStatistics content_score = new DoubleSummaryStatistics(); 
    private DoubleSummaryStatistics teach_score = new DoubleSummaryStatistics(); 

    public void add(ScoreInfo si) { 
     cove_score.accept(si.cove_score); 
     theam_score.accept(si.theam_score); 
     content_score.accept(si.content_score); 
     teach_score.accept(si.teach_score); 
    } 

    public ScoreInfoAccumulator combine(ScoreInfoAccumulator sia) { 
     cove_score.combine(sia.cove_score); 
     theam_score.combine(sia.theam_score); 
     content_score.combine(sia.content_score); 
     teach_score.combine(sia.teach_score); 
     return this; 
    } 

    public ScoreInfoAverage average() { 
     return new ScoreInfoAverage((float) cove_score.getAverage(), 
     (float) theam_score.getAverage(), (float) content_score.getAverage(), 
     (float) teach_score.getAverage()); 
    } 
    } 
    return Collector.of(ScoreInfoAccumulator::new, ScoreInfoAccumulator::add, 
     ScoreInfoAccumulator::combine, ScoreInfoAccumulator::average); 
} 

最後但並非最不重要的,你添加Collector下游:

Map<ScoreInfoP, ScoreInfoAverage> collect = scoreInfos.stream() 
     .collect(Collectors.groupingBy(ScoreInfo::getScoreInfoP, scoreInfoToAverage())); 
+0

我覺得有點太...你可以簡單地添加它們,然後分割;幾乎與普通的'Collectors.average ...'一樣 – Eugene

+0

@Eugene爲什麼重複一遍又一遍? – Flown

+0

我不認爲你的評論是誠實的 – Eugene