Saurabh Prajapati
Saurabh Prajapati

Reputation: 332

How do I convert following code to streams

I have a list how can I convert it to a Map in which I can have keys with minimum value as key value pair. I want to convert this code to streams.

Map<Long, Date> formToDate = new HashMap<>();
    for(FormInstance formInstance : formInstances) {
        if(formToDate.get(formInstance.getForm().getId()) == null) {
            formToDate.put(formInstance.getForm().getId(), formInstance.getCreatedDate());
        }
        else{
            Date prevDate = formToDate.get(formInstance.getForm().getId());
            Date thisDate = formInstance.getCreatedDate();
            formToDate.put(formInstance.getForm().getId(), prevDate.before(thisDate) ? prevDate : thisDate);
        }
    }

to something like this:

Map<Long, List<Date>> formToDate = formInstances.stream()
            .collect(
                    Collectors.groupingBy(formInstance -> formInstance.getForm().getId(),
                            Collectors.mapping(FormInstance::getCreatedDate, Collectors.toList())));

But instead of returning list all I want to have the smallest date.

Upvotes: 0

Views: 110

Answers (3)

Eran
Eran

Reputation: 393791

Another option is to use Collectors.groupingBy in combination of Collectors.mapping and Collectors.minBy:

Map<Long, Optional<Date>> formToDate =
    formInstances.stream()
                 .collect(Collectors.groupingBy(fi -> fi.getForm().getId(),
                                                Collectors.mapping(FormInstance::getCreatedDate,
                                                                   Collectors.minBy(Date::compareTo))));

Upvotes: 0

Malte Hartwig
Malte Hartwig

Reputation: 4555

Flown's answer is nice if you really want to use streams, but often it is possible to do without while still taking advantage of newer Java features. I have seen many cases (myself included) in which streams were used for the sake of using streams instead of taking a simpler, more direct approach.

If you already have a list and want to avoid creating a stream, you can use the new Map.merge() method:

Map<Long, Date> minimum = new HashMap<>();
forms.forEach(form -> minimum.merge(form.getForm().getId(),
                                    form.getCreatedDate(),
                                    (date, date2) -> date.before(date2) ? date : date2));

Aside from merge, Map has many methods that can make things like this easier: computeIfAbsent, getOrDefault, or even the "old" containsKey method can make code a lot more readable by replacing common boilerplate snippets, like the one you used:

if (map.get(key) == null) { add } else { test and put }

Upvotes: 0

Flown
Flown

Reputation: 11740

There is a Collector::toMap implementation which provides a merge function. This can be used to determine the smallest date from two different entries with same id like:

Map<Long, Date> minimum = formInstances.stream().collect(Collectors.toMap(
        fi -> fi.getForm().getId(), 
        FormInstance::getCreatedDate, 
        (date, date2) -> date.before(date2) ? date : date2
));

Upvotes: 1

Related Questions