Group and summarize a list on a map using Lambda

I have a list of MoveTrack objects that I want to group by month, and count and store data in Map<String, Double> . I am trying to learn Lambda and experiment with it, trying to do this task with 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<>(); 

Thus, I want to be able to group the moveTracking list and summarize the values ​​in movMap , with each card key = month (January, February, etc.) and the corresponding value, which is the amount of movement, the amount doubles for this month.

+5
source share
3 answers

Collectors.groupingBy Allows you to reduce a list to a map, where the key is some manipulation of the list item, and the value is some kind of aggregate function applied to the item manipulation. In your case, you can use something like this:

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

If you are open to using a third-party library, Eclipse Collections has specialized methods called sumBy that work well with lambdas.

If you use the MutableList from Eclipse Collections for the moveTracking list, the code looks like this:

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

It is up to you to determine where and how you want to implement getMonthName() . You will notice that sumByDouble returns an ObjectDoubleMap . This means that you can use double for your movementAmount , and it will not fit during the summation.

If you want to keep your List<MoveTrack> type as it is at present, you can use the ListAdapter or Iterate to accomplish the same thing.

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

Note: I am a committer for Eclipse collections

+6
source

Use Collectors.groupingBy as follows:

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

Code for you;)

 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; } } 
+2
source

Source: https://habr.com/ru/post/1243494/


All Articles