6

Say I have the following map:

Map<Member, List<Message>> messages = ... //constructed somehow

I would like to use the java 8 stream api in order to obtain a:

SortedMap<Message, Member> latestMessages = ...

Where the comparator passed into the SortedMap/TreeMap would be based on the message sendDate field.

Furthermore, of the list of sent messages, I would select the latest message which would become the key to the sorted map.

How can I achieve that?

edit 1:

Comparator<Message> bySendDate = Comparator.comparing(Message::getSendDate);
SortedMap<Message, Member> latestMessages = third.entrySet().stream()
        .collect(Collectors.toMap(e -> e.getValue().stream().max(bySendDate).get(), Map.Entry::getKey, (x, y) -> {
            throw new AssertionError();
        }, () -> new TreeMap(bySendDate.thenComparing(Comparator.comparing(Message::getId)))));

I get the following compilation error:

The method collect(Collector<? super T,A,R>) in the type Stream<T> is not applicable for the arguments (Collector<Map.Entry<Member,List<Message>>,?,TreeMap>)
7
  • 1
    Are you sure that you want this? That will imply that there can be only one Message with a specific sendDate, even if different message with the same date but different sender and receiver exist. Commented Mar 2, 2015 at 16:41
  • Yes. Basically I will have the latest message sent to or from a given member. Commented Mar 2, 2015 at 16:44
  • I am actually implementing a message box such as the one on what'sapp or hangout, etc... Commented Mar 2, 2015 at 16:45
  • Oh, I am with you now! You're right. Let me edit my question.... Commented Mar 2, 2015 at 16:47
  • @Holger I think it's the same question as this one: stackoverflow.com/questions/28810301/… I've come up with something; but maybe you have a better implementation (the question was not clear to me at first). ;-) Commented Mar 2, 2015 at 16:49

1 Answer 1

13

Let’s dissolve this into two parts.

First, transform Map<Member, List<Message>> messages into a Map<Message, Member> latestMessages by reducing the messages for a particular communication partner (Member) to the latest:

Map<Message, Member> latestMessages0 = messages.entrySet().stream()
    .collect(Collectors.toMap(
        e -> e.getValue().stream().max(Comparator.comparing(Message::getSendDate)).get(),
        Map.Entry::getKey));

Here, the resulting map isn’t sorted but each mapping will contain the latest message shared with that participant.


Second, if you want to have the resulting map sorted by sendDate, you have to add another secondary sort criteria to avoid losing Messages which happen to have the same date. Assuming that you have a Long ID that is unique, adding this ID as secondary sort criteria for messages with the same date would be sufficient:

Comparator<Message> bySendDate=Comparator.comparing(Message::getSendDate);
SortedMap<Message, Member> latestMessages = messages.entrySet().stream()
   .collect(Collectors.toMap(
       e -> e.getValue().stream().max(bySendDate).get(),
       Map.Entry::getKey, (x,y) -> {throw new AssertionError();},
       ()->new TreeMap<>(bySendDate.thenComparing(Comparator.comparing(Message::getId)))));

Since sorting by the unique IDs should solve any ambiguity, I provided a merge function which will unconditionally throw, as calling it should never be required.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks very much. However I am running into the above error... I have edited my post accordingly.
Which compiler do you use? Note that new TreeMap(…) should be new TreeMap<>(…), I forgot this <> thing but my compiler produces a warning only (and only with -Xlint) but maybe your compiler is more picky…
Exactly what I needed today ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.