【问题标题】:How to sort ArrayList of objects by timestamp and get last five elements如何按时间戳对对象的 ArrayList 进行排序并获取最后五个元素
【发布时间】:2018-10-24 18:14:07
【问题描述】:

我正在开发一个简单的聊天应用程序。我需要按时间戳对聊天消息进行排序并获取最后五个元素。

我就是这样做的。它有效,但我不确定这是否是最好的方法。您觉得还有改进的余地吗?

private ArrayList<ChatMessage> chatMessages = new ArrayList<>();
private ArrayList<ChatMessage> finalChatMessages = new ArrayList<>();


public ArrayList<ChatMessage> addNewChatMessage(ChatMessage chatMessage) {

    //receive new chat message
    if (!chatMessages.contains(chatMessage)) {
        chatMessages.add(chatMessage);
    } else {
        int pos = chatMessages.indexOf(chatMessage);
        chatMessages.set(pos, chatMessage);
    }

    //sort chat messages by timestamp
    Collections.sort(chatMessages, new Comparator<ChatMessage>() {
        public int compare(ChatMessage o1, ChatMessage o2) {
            if (o1.getTimestamp() == o2.getTimestamp())
                return 0;
            return o1.getTimestamp() < o2.getTimestamp() ? -1 : 1;
        }
    });


    //get latest five messages
    List<ChatMessage> tail = chatMessages.subList(Math.max(chatMessages.size() - 5, 0), chatMessages.size());

    finalChatMessages.clear();


    //add new messages to the final list
    for (ChatMessage chatMessage : tail) {
        finalChatMessages.add(chatMessage);
    }

    return finalChatMessages;
}

【问题讨论】:

  • 你可以在代码审查中发布这个问题,因为它有效而且它不是一个真正的问题。
  • 如果此代码正常运行,您应该在我们的姐妹网站Code Review 上发布。
  • @mychemicalro 仅供参考,您可以使用 [CodeReview.SE] 在 cmets 中创建链接。这适用于所有 Stack Exchange 站点。关键是找到正确的前缀。

标签: java arraylist


【解决方案1】:

我看到 3 个地方需要稍微改进:

  1. 不要扫描chatMessages 两次(containsindexOf):

    int pos = chatMessages.indexOf(chatMessage);
    if (pos == -1) {
        chatMessages.add(chatMessage);
    } else {
        chatMessages.set(pos, chatMessage);
    }
    
  2. 使用Timestamp.compareTo:

    Collections.sort(chatMessages, new Comparator<ChatMessage>() {
        @Override
        public int compare(ChatMessage o1, ChatMessage o2) {
            return o1.getTimestamp().compareTo(o2.getTimestamp());
        }
    });
    

    在 Java 8+ 中:

    Collections.sort(chatMessages, Comparator.comparing(ChatMessage::getTimestamp));
    
  3. 使用ArrayList.addAll

    finalChatMessages.clear();
    finalChatMessages.addAll(chatMessages.subList(Math.max(chatMessages.size() - 5, 0), chatMessages.size()));
    

【讨论】:

  • 谢谢。该项目仍然基于 Java 7。
【解决方案2】:

经过改进的规范流解决方案是:

int pos = chatMessages.indexOf(chatMessage);
if (pos == -1) {
    chatMessages.add(chatMessage);
} else {
    chatMessages.set(pos, chatMessage);
}

List<ChatMessage> tail = chatMessages.stream()
    .sorted(Comparator.comparing(ChatMessage::getTimestamp))
    .skip(Math.max(0, chatMessages.size() - 5))
    .collect(Collectors.toList());

finalChatMessages.clear();
finalChatMessages.addAll(tail);

值得一提的是,将整个列表排序为仅保留最后 5 个元素可以在时间复杂度方面有所改进。排序为O(NlogN)N 是列表的总大小。如果您想将解决方案改进为 O(Nlog5),请查看 this answer

【讨论】:

  • .sorted(Comparator.comparing(ChatMessage::getTimestamp).reversed()).limit(5)
  • @shmosel 会以错误的方向返回元素
  • 好点。虽然尚不完全清楚顺序在结果列表中是否重要。
【解决方案3】:

您可以使用 java-8 功能对列表进行排序:

Collections.sort(chatMessages, (o1, o2) -> o1.getTimestamp().compareTo(o2.getTimestamp()));

由于您只需要最后 5 个元素,因此您可以遍历此列表

【讨论】:

    【解决方案4】:

    使用 Java 8 功能:

    //sort chat messages by timestamp and get latest 5 messages
    chatMessages.sort(comparing(ChatMessage::getTimestamp));
    int toSkip = Math.max(chatMessages.size() - 5, 0);
    finalChatMessages = chatMessages.stream().skip(toSkip).collect(toCollection(ArrayList::new));
    return finalChatMessages;
    

    比较是从类 java.util.Comparator 的静态导入,toCollection 是从 java.util.stream.Collectors。

    如果你的方法返回 List 而不是 ArrayList,那就更简单了:

    //sort chat messages by timestamp and get latest 5 messages
    chatMessages.sort(comparing(ChatMessage::getTimestamp).reversed());
    int toSkip = Math.max(chatMessages.size() - 5, 0);
    finalChatMessages = chatMessages.stream().skip(toSkip).collect(toList());
    return finalChatMessages;
    

    【讨论】:

    • 代码返回五条消息,而不是所需的最后五条消息。
    • 添加 reversed() 使其返回最后五个错误的顺序。
    • 这样比较好,但是倒序排序和原题不一样,因为顺序是颠倒的。你应该 .skip(chatMessages.size() - 5) 代替,没有反向比较器
    • 另外,代码不会根据需要替换现有finalChatMessages 列表的内容。
    猜你喜欢
    • 2017-06-26
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 2018-08-09
    • 1970-01-01
    相关资源
    最近更新 更多