2017-07-14 82 views
2

我有流分組的問題。流分組由一個字段然後合併所有其他

List<FAR> listFar = farList.stream().filter(f -> !f.getStatus().equals(ENUM.STATUS.DELETED)) 
      .collect(Collectors.toList()); 
List<HAUL> haulList = listFar.stream().map(f -> f.getHaul()).flatMap(f -> f.stream()) 
      .collect(Collectors.toList()); 

它按物種分組,但一切都很好,但HAUL還有其他屬性。

Map<Specie, List<HAUL>> collect = haulList.stream().collect(Collectors.groupingBy(HAUL::getSpecie)); 

屬性:

  1. haul.getFishCount();(整數)
  2. haul.getFishWeight();(BigDecimal)的

是否有可能組由HAUL::getSpecie(由種),而且 「合併」 在一起那兩個額外的領域,所以我有總計?

例如:我有3個HAUL元素,其中魚類物種A的重量爲50/30/10千克。

我可以按品種分組並且總重量是多少?

+0

你的意思是把這些加在一起? 'getFishWeight'和'getFishCount'?或每個單獨的總和? – Eugene

+0

按物種分組,然後通過getFishCount()和getFishWeight()獲得HAUL對象 - 所以這兩個字段具有每個物種的總和(因爲它們被分組)。 – Kefirchiks

+0

一般而言 - 每個分組物種的獨立字段。 – Kefirchiks

回答

4

如果我理解正確的:

haulsList 
     .stream() 
     .collect(Collectors.groupingBy(HAUL::getSpecie, 
       Collectors.collectingAndThen(Collectors.toList(), 
        list -> { 
        int left = list.stream().mapToInt(HAUL::getFishCount).sum(); 
        BigDecimal right = list.stream().map(HAUL::getFishWeight).reduce(BigDecimal.ZERO, (x, y) -> x.add(y)); 
        return new AbstractMap.SimpleEntry<>(left, right); 
        }))); 

有做一個表格:

.stream() 
.collect(Collectors.groupingBy(HAUL::getSpecie, 
       Collectors.summingInt(HAUL::getFishCount))); 

.stream() 
.collect(Collectors.groupingBy(HAUL::getSpecie, 
      Collectors.mapping(HAUL::getFishWeight, Collectors.reducing((x, y) -> x.add(y))))); 

但你不能真正使這些在該法同時。

+0

謝謝您的解決方案! – Kefirchiks

3

您可以使用mappingreduce例如:

class Foo { int count; double weight; String spice; } 
List<Foo> fooList = Arrays.asList(
    new Foo(1,new BigDecimal(10), "a"), 
    new Foo(2,new BigDecimal(38), "a"), 
    new Foo(5,new BigDecimal(2), "b"), 
    new Foo(4,new BigDecimal(8), "b")); 

Map<String,Optional<BigDecimal>> spieceWithTotalWeight = fooList.stream(). 
     collect(
       groupingBy(
         Foo::getSpice, 
         mapping(
           Foo::getWeight, 
           Collectors.reducing(BigDecimal::add) 
         ) 
       ) 
     ); 
System.out.println(spieceWithTotalWeight); // {a=Optional[48], b=Optional[10]} 

我希望這有助於。

+0

我有Integer(count)和BigDecimal作爲權重。 你總結的是什麼意思? – Kefirchiks

+0

@Kefirchiks,我已經更新了我的答案。我認爲體重有雙重類型。我很抱歉的混淆。 –

3

如果我正確地得到你的問題,你想每個物種的總數count * weight

您可以通過使用Collectors.groupingBy與下游收集器減少了在每個物種的HAUL列表中的haul.getFishCount() * haul.getFishWeight()總和做到這一點:

Map<Specie, BigDecimal> result = haulList.stream() 
    .collect(Collectors.groupingBy(haul -> haul.getSpecie(), 
     Collectors.mapping(haul -> 
       new BigDecimal(haul.getFishCount()).multiply(haul.getFishWeight()), 
      Collectors.reducing(BigDecimal::plus)))); 

這將得到count * weight每個物種的總和。如果你可以將以下方法添加到您的Haul類:

public BigDecimal getTotalWeight() { 
    return new BigDecimal(getFishCount()).multiply(getFishWeight()); 
} 

然後,收集流會更容易和更具可讀性:

Map<Specie, BigDecimal> result = haulList.stream() 
    .collect(Collectors.groupingBy(haul -> haul.getSpecie(), 
     Collectors.mapping(haul -> haul.getTotalWeight(), 
      Collectors.reducing(BigDecimal::plus)))); 

編輯:畢竟,似乎你想爲每個領域單獨的總和...

我會使用Collectors.toMap與此合併功能。下面的代碼:

Map<Specie, List<BigDecimal>> result = haulList.stream() 
    .collect(Collectors.toMap(
     haul -> haul.getSpecie(), 
     haul -> Arrays.asList(
      new BigDecimal(haul.getFishCount()), 
      haul.getFishWeight()), 
     (list1, list2) -> { 
      list1.set(0, list1.get(0).plus(list2.get(0))); 
      list1.set(1, list1.get(1).plus(list2.get(1))); 
      return list1; 
     })); 

它使用2個元素的列表,以存儲在索引0魚計數和魚體重索引1每一個硬幣。

+0

適用於繁殖目的。但我只是想分組,然後獲得單獨元素的總和。 – Kefirchiks

+0

@Kefirchiks我已經更新了答案,以顯示總結兩個單獨的字段。 –

相關問題