2016-02-21 15 views
5

Ho un elenco di oggetti MoveTrack che desidero raggruppare per mese e contare e memorizzare i dati in un Map<String, Double>. Sto cercando di imparare Lambda e sperimentarlo così cercando di fare questo compito con Lambda.Raggruppamento e somma di una lista in una mappa utilizzando 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<>(); 

quindi voglio essere in grado di raggruppare l'elenco moveTracking e sommare i valori nella movMap, con ogni Map Key = Month Nome (gennaio, febbraio, etc.) e il valore corrispondente alla quantità di movimento che è un somma dei doppi per quel mese.

+3

Beh, hai provato ancora nulla? Sospetto che tu voglia utilizzare 'Stream.collect' e' Collectors.groupingBy'. –

+1

E Collectors.summingDouble come collector downstream –

+0

@JonSkeet yes ha tentato groupBy e toMap con nient'altro che errori. Soprattutto quando ho iniziato a inserire il simpledateformater. – Aeseir

risposta

5

Collectors.groupingBy Consente di ridurre un elenco a una mappa in cui la chiave è una manipolazione dell'elemento dell'elenco e il valore è una funzione di aggregazione applicata a una manipolazione dell'elemento. Nel tuo caso, si potrebbe usare qualcosa di simile:

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

Usa Collectors.groupingBy come segue:

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))); 

Codice per voi;)

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

Se siete aperti per utilizzare una libreria di terze parti, lo Eclipse Collections ha metodi specializzati chiamati sumBy che funzionano bene con lambda.

Se si utilizza MutableList da Eclipse collezioni per la lista moveTracking, il codice apparirebbe come segue:

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

Sta a voi decidere dove e come si desidera implementare getMonthName(). Noterai che sumByDouble restituisce un ObjectDoubleMap. Ciò significa che è possibile utilizzare double per il proprio movementAmount e che non verrà inserito durante la somma.

Se si desidera mantenere il vostro tipo List<MoveTrack> come è attualmente, è possibile utilizzare una o la classe di utilità IterateListAdapter per ottenere la stessa cosa.

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

Nota: Sono un committer per Eclipse Collezioni

Problemi correlati