使用java 8流API将地图转换为另一个地图

bal*_*teo 5 dictionary java-8 java-stream

说我有以下地图:

Map<Member, List<Message>> messages = ... //constructed somehow
Run Code Online (Sandbox Code Playgroud)

我想使用java 8 stream api来获取:

SortedMap<Message, Member> latestMessages = ...
Run Code Online (Sandbox Code Playgroud)

传递给SortedMap/TreeMap的比较器将基于消息sendDate字段.

此外,在已发送消息列表中,我将选择最新消息,该消息将成为已排序映射的关键.

我怎样才能做到这一点?

编辑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)))));
Run Code Online (Sandbox Code Playgroud)

我收到以下编译错误:

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>)
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 10

让我们将其分解为两部分.

首先,通过特定通信伙伴()的消息减少到最新消息来转换Map<Member, List<Message>> messages为a :Map<Message, Member> latestMessagesMember

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

此处,结果map未排序,但每个映射将包含与该参与者共享的最新消息.


其次,如果您希望将结果映射按sendDate排序,则必须添加另一个辅助排序条件,以避免丢失Messages具有相同日期的情况.假设您有一个Long唯一的ID,将此ID添加为具有相同日期的消息的辅助排序条件就足够了:

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)))));
Run Code Online (Sandbox Code Playgroud)

由于按唯一ID排序应解决任何歧义,我提供了一个无条件抛出的合并函数,因为永远不需要调用它.

  • 你用哪个编译器?请注意,`new TreeMap(...)`应该是`new TreeMap <>(...)`,我忘了这个`<>`的东西但是我的编译器只产生一个警告(并且只用`-Xlint`)但是你的编译器可能是更挑剔...... (2认同)