I have a list of MoveTrack
objects that i want to group by Month and count and store the data in a Map<String, Double>
. I am trying to learn Lambda and experiment with it so 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<>();
So I want to be able to group the moveTracking
list and sum the values into the movMap
, with each Map Key = Month Name (January, February, etc.) and corresponding Value the movement amount which is a sum of doubles for that month.
Collectors.groupingBy
Allows you to reduce a list to a map where the key is some manipulation of the list's element and the value is some aggregate function applied to a manipulation of the element.
In your case, you could 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)));
If you're open to using a third-party library, Eclipse Collections has specialized methods called sumBy
that work well with lambdas.
If you use MutableList
from Eclipse Collections for the moveTracking list, the code would look as follows:
MutableList<MoveTrack> moveTracking = Lists.mutable.empty();
ObjectDoubleMap<String> doubleMap =
moveTracking.sumByDouble(MoveTrack::getMonthName, MoveTrack::getMovementAmount);
It's up to you to determine where and how you want to implement getMonthName()
. You'll notice that sumByDouble
returns an ObjectDoubleMap
. This means you can use double
for your movementAmount
and it will not be boxed during the summing.
If you want to keep your List<MoveTrack>
type as it currently is, you can either use a ListAdapter
or the Iterate
utility class 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
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With