2016-02-21 3 views
5

У меня есть список MoveTrack объектов, которые я хочу сгруппировать по месяцам, и посчитайте и сохраните данные в Map<String, Double>. Я пытаюсь изучить Лямбду и экспериментировать с ней, пытаясь сделать эту задачу с Лямбдой.Группировка и суммирование списка на карте с использованием 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<>(); 

Так что я хочу, чтобы иметь возможность группировать moveTracking список и просуммировать значения в movMap, с каждой карты Key = название месяца (январь, февраль и т.д.) и соответствующее значение сумма движение, которое является сумма удваивается за этот месяц.

+3

Ну, вы пробовали что-нибудь еще? Я подозреваю, что вы хотите использовать 'Stream.collect' и' Collectors.groupingBy'. –

+1

И Collectors.summingDouble как нисходящий коллекционер –

+0

@JonSkeet да попытка groupBy и toMap с ошибками. Особенно, когда я начал вводить упрощенную форму. – Aeseir

ответ

5

Collectors.groupingBy Позволяет сводить список к карте, где ключ является некоторой манипуляцией с элементом списка, а значение представляет собой некоторую совокупную функцию, применяемую к манипуляции с элементом. В вашем случае, вы могли бы использовать что-то вроде этого:

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

Использование Collectors.groupingBy следующим образом:

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

код для вас;)

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

Если вы открыты для использования сторонней библиотеки, Eclipse Collections имеет специализированные методы, называемые sumBy, которые хорошо работают с лямбды.

Если вы используете MutableList из Eclipse, коллекции для списка moveTracking, код будет выглядеть следующим образом:

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

Это до вас, чтобы определить, где и как вы хотите реализовать getMonthName(). Вы заметите, что sumByDouble возвращает ObjectDoubleMap. Это означает, что вы можете использовать double для вашего movementAmount, и он не будет помещаться во время суммирования.

Если вы хотите сохранить свой List<MoveTrack> тип в его нынешнем виде, вы можете использовать ListAdapter или Iterate класс полезности для достижения этой же цели.

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

Примечание: Я коммиттер для Eclipse, Коллекции

Смежные вопросы