在包含日期的对象列表中搜索

时间:2014-11-23 00:30:23

标签: java list search

假设我有一个List<Message> conversation字段的消息Date列表。

public class Message {
    private Date time;
    ...
}

我希望在一个时间范围内找到所有邮件,由两个Date个对象fromDatetoDate分隔:

public List<Message> getMessagesInRange(final Date fromDate, final Date toDate, final List<Message> conversation) {
    List<Message> messagesInRange = new ArrayList<Message>();
    ...
    return messagesInRange;
}

消息列表按时间排序(较旧的消息在较新的消息之前添加)。现在,我可以从头开始遍历整个列表,并填充messagesInRange添加指定范围内的所有消息。一旦我达到比toDate更近的日期,我可以结束迭代,因为我知道列表已经排序。

但也许在指定范围内没有消息,从头开始迭代是浪费时间。我想知道一种有效的方法来获取列表中第一个消息的引用,并从那里进行迭代。也许这可以通过二分搜索来完成?

1 个答案:

答案 0 :(得分:1)

  • 实施消息比较器;
  • 使用SortedSet存储邮件的排序结构。

Java代码:

MessageComparator messageComparator = new MessageComparator();
SortedSet<Message> allMessages = new TreeSet<>(messageComparator);

public List<Message> getMessagesInRange(final Date fromDate, final Date toDate, final List<Message> conversation) {
    return new ArrayList<Message>(allMessages.subSet(
        messageComparator.minFrom(fromDate), true,  messageComparator.maxFrom(toDate), true).values());
}

实施例子:

public class Message {
    private static final AtomicLong ID_COUNTER = new AtomicLong();
    private final long timestamp;
    private final String text;
    private final long id;

    public Message(Date time, String text) {
        this(time, text, ID_COUNTER.incrementAndGet());
    }

    private Message(Date time, String text, long id) {
        this.timestamp = time.getTime(); // (a) Date is mutable & (b) better memory consumption
        this.text = text == null ? "" : text;
        this.id = id;
    }

    ... // getters & logic (if any)

    // Keep in mind - equals & compareTo should be in sync.
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (null == obj) {
            return false;
        }
        if (!obj.getClass().equals(getClass())) {
            return false;
        }
        Message that = (Message) obj;
        return timestamp == that.timestamp && id == that.id && message.equals(that.message);
    }
}

public class MessageComparator implements Comparator<Message> {
    // Keep in mind - equals & compareTo should be in sync.
    public int compare(Message m1, Message m2) {
        if (m1 == null ? m2 == null : m1.equals(m2)) {
            return 0;
        }
        if (m1 == null) {
            return -1;
        }
        if (m2 == null) {
            return 1;
        }
        int c = Long.compare(m1.timestamp, m2.timestamp);
        if (c != 0) {
            return c;
        }
        c = m1.text.compareTo(m2.text);
        if (c != 0) {
            return c;
        }
        c = Long.compare(m1.id, m2.id);
        return c;
    }

    public Message minFrom(Date date) {
        return new Message(new Date(date.getTime()), null, -1);
    }

    public Message maxFrom(Date date) {
        return new Message(new Date(date.getTime() + 1), null, -1);
    }
}