2016-02-21 6 views
5

Mam listę obiektów, które chcę grupować według miesięcy i liczyć i przechowywać dane w Map<String, Double>. Próbuję nauczyć się Lambdy i eksperymentować z nią, próbując to zrobić z Lambdą.Grupowanie i podsumowywanie listy na mapie przy użyciu Lambda

class MoveTrack { 
private Date time; 
private Double movementAmount; 

//getters and setters 
} 

// in my main method 
List<MoveTrack> mveTracking = new ArrayList<>(); 
Map<String, Double> movMap = new HashMap<>(); 

Więc chcę móc grupy lista moveTracking i zsumować wartości do movMap, z każdej mapie key = nazwa miesiąca (styczeń, luty, etc.) i odpowiednia wartość kwota ruch, który jest suma debel za ten miesiąc.

+3

Cóż, czy próbowałeś już coś? Podejrzewam, że chcesz użyć 'Stream.collect' i' Collectors.groupingBy'. –

+1

I Collectors.summingDouble jako kolektor poniżej poziomu –

+0

@JonSkeet tak próbował groupBy i toMap z niczym, ale błędy. Zwłaszcza, gdy zacząłem wstawiać do symulatora. – Aeseir

Odpowiedz

5

Collectors.groupingBy Umożliwia zmniejszenie listy do mapy, na której kluczem jest manipulacja elementem listy, a wartość jest jakąś funkcją agregującą zastosowaną do manipulacji elementem. W twoim przypadku, można użyć coś takiego:

SimpleDateFormat monthFormatter = new SimpleDateFormat("MMM"); 
Map<String, Double> moveMap = 
    moveTracking.stream() 
       .collect(Collectors.groupingBy 
        (m -> monthFormatter.format(m.getTime()), 
        Collectors.summingDouble(MoveTrack::getMovementAmount))); 
2

Zastosowanie Collectors.groupingBy następująco:

mveTracking.stream().collect(Collectors.groupingBy(m -> { 
      final Calendar cal = Calendar.getInstance(); 
      cal.setTime(m.getTime()); 
      final int month = cal.get(Calendar.MONTH); 
      return new DateFormatSymbols().getMonths()[month]; 
     }, Collectors.summingDouble(MoveTrack::getMovementAmount))); 

kod dla Ciebie;)

import java.text.DateFormatSymbols; 
import java.util.ArrayList; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Collectors; 

public class GroupList { 
    public static void main(String[] args) { 
     List<MoveTrack> mveTracking = new ArrayList<>(); 
     mveTracking.add(new MoveTrack(new Date(), 10.0d)); 
     mveTracking.add(new MoveTrack(new Date(), 11.0d)); 
     Map<String, Double> movMap = new HashMap<>(); 
     movMap = mveTracking.stream().collect(Collectors.groupingBy(m -> { 
      final Calendar cal = Calendar.getInstance(); 
      cal.setTime(m.getTime()); 
      final int month = cal.get(Calendar.MONTH); 
      return new DateFormatSymbols().getMonths()[month]; 
     }, Collectors.summingDouble(MoveTrack::getMovementAmount))); 
     System.out.println(movMap); 
    } 
} 

final class MoveTrack { 

    private final Date time; 
    private final Double movementAmount; 

    public MoveTrack(final Date time, final Double movementAmount) { 
     this.time = new Date(time.getTime()); 
     this.movementAmount = movementAmount; 
    } 

    public Date getTime() { 
     return time; 
    } 

    public Double getMovementAmount() { 
     return movementAmount; 
    } 
} 
6

Jeśli jesteś otwarty do korzystania z biblioteki innej firmy, Eclipse Collections ma wyspecjalizowane metody o nazwie sumBy, które działają dobrze z lambdas.

Jeśli używasz MutableList z Eclipse Kolekcje na liście moveTracking, kod wyglądałby następująco:

MutableList<MoveTrack> moveTracking = Lists.mutable.empty(); 
ObjectDoubleMap<String> doubleMap = 
    moveTracking.sumByDouble(MoveTrack::getMonthName, MoveTrack::getMovementAmount); 

To do ciebie, aby określić, gdzie i jak chcesz wdrożyć getMonthName(). Zauważysz, że sumByDouble zwraca ObjectDoubleMap. Oznacza to, że możesz użyć double dla swojego movementAmount i nie będzie to pudełko w trakcie podsumowania.

Jeśli chcesz zachować swój typ List<MoveTrack> w obecnej postaci, możesz użyć klasy narzędziowej ListAdapter lub Iterate, aby wykonać to samo.

List<MoveTrack> list = ...; 
ObjectDoubleMap<String> doubleMap = 
    Iterate.sumByDouble(list, MoveTrack::getMonthName, MoveTrack::getMovementAmount); 

Uwaga: Jestem committer dla Eclipse Kolekcje