2016-05-12 20 views
4

を一覧表示し、合計する要素を追加し、私は私がlistOfPricedObjects上の1つのストリーム操作を使用して次の行うことができると信じて:Javaの8ストリーム

List<BigDecimal> myList = new ArrayList(); 
myList = listOfPricedObjects.stream().map(PricedObject::getPrice).collect(Collectors.toList()); 
BigDecimal sum = listOfPricedObjects.stream().map(PricedObject::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add) 

私は価格ではmyListを記入し、ストリーム1時間を使って価格の合計を計算するにはどうすればよいですか? ありがとう

UPD:その結果、myListにpriceとsum変数を足したものが必要です。しかし、それを2回ストリーム()を使ってではありません。あなたが使用することができます

+4

ストリーム要素をまとめて変数に集計しながらストリームに集約すると、ストリームには好ましくない副作用が発生します(OracleドキュメントのStreamsで説明されています) –

+0

メソッドのクリーンコードの概念には何が1つしかありません。 –

答えて

6

peekそして、還元

List<BigDecimal> newList = new ArrayList<>(); 
BigDecimal sum = list.stream() 
        .map(PricedObject::getPrice) 
        .peek(newList::add) 
        .reduce(BigDecimal.ZERO, BigDecimal::add); 

をかけながらを使用してに興味があればTunakiの答えを見てください新しいlistに追加sumは難解な並行タスクであるため意味をなさない非並行コレクションを持つです。

+0

newListは最初のリストと同じ価格順序を常に持っていますか? – Jack

2

)あなたがリストにパススルー値を追加

BigDecimal sum = listOfPricedObjects.stream() 
            .map(o -> { 
             myList.add(o); 
             return o;}) 
            .map(PricedObject::getPrice) 
            .reduce(BigDecimal.ZERO, BigDecimal::add) 

をマッピングアイデンティティを行うことができます。しかし、私は(PEEKを使用してSleiman Jneidiの解決のために行くだろう、そのよりエレガントな

+0

私は価格もいっぱいのmyListが必要です。あなたの例は、単に合計を取得します。 – Jack

+0

は「パススルー」マッピングを忘れましたが、これは今役立つのですか? –

+0

はい、ありがとうございます!この例ではマップを互いに変更できるように見えます。 – Jack

7

あなたがここで欲しいのは、2つのコレクターの中にあなたの要素を集めることです:最初のものはリストに集め、もう1つは価格を合計します。

Stream API自体にこのようなコレクタがないため、独自のストリームを簡単に作成できます。ストリームパイプラインの結果を保持するクラスResultHolderを作成しましょう。これは小数点と合計のリストです。これは、並列パイプラインで動作し、他の回答に反して、リストの最初の秩序を維持します

ResultHolder resultHolder = 
    listOfPricedObjects.stream() 
      .map(PricedObject::getPrice) 
      .collect(
       ResultHolder::new, 
       (r, p) -> { r.list.add(p); r.sum = r.sum.add(p); }, 
       (r1, r2) -> { r1.list.addAll(r2.list); r1.sum = r1.sum.add(r2.sum); } 
      ); 
System.out.println(resultHolder.list); 
System.out.println(resultHolder.sum); 

class ResultHolder { 
    List<BigDecimal> list = new ArrayList<>(); 
    BigDecimal sum = BigDecimal.ZERO; 
} 

最後に、我々はでそれを使用することができます。

+1

これは 'Stream' APIの唯一のクリーンなソリューションです。 – Flown

4

listOfPricedObjectsのような任意のストリームをソースから再作成できないため、1回だけトラバースされるユースケースを想定することは合理的かもしれませんが、Collectors.toList()経由で生成されたリストを効率的にトラバースできると仮定できます。

List<BigDecimal> myList = listOfPricedObjects.stream() 
    .map(PricedObject::getPrice).collect(Collectors.toList()); 
BigDecimal sum = myList.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO); 

ありここにはコードの重複がなく、1つのストリームトラバースにこれら2つの無関係な操作を実行しようとすると、任意の恩恵なしで、コードが複雑になります。

+0

答えをありがとう。 myList.stream()は非効率的な新しいストリームを作成してはいけませんか? – Jack

+1

'Collectorsによって返されたリスト。toList() 'を効率的にトラバースすることができます(現在は単にArrayListです)。ストリームから作成されたストリームは、その能力を取り巻くラッパーにすぎません。ストリームはそのリストの内部配列を反復します。高速で横断できるデータ構造はJavaではありません... – Holger

関連する問題