组合重叠日期范围 - Java [英] Combining Overlapping Date Ranges - Java

查看:95
本文介绍了组合重叠日期范围 - Java的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Task类看起来像以下(使用Java 8 Time API)。

I have a Task class which looks like the following (using Java 8 Time API).

class Task {
    LocalDateTime start;
    LocalDateTime end;
    Set<String> actionItems;
}

我有两个排序(第一个开始,然后是结束)任务实例,让我们说列表<任务> tasksList1 列表<任务> tasksList2 。我想组合重叠的任务(通过在需要的情况下打破任务,并将来自重叠的其他任务的actionItem添加到一个新的任务对象中)。

I have two sorted (first by start, then by end) lists containing such Task instances, lets say List<Task> tasksList1 and List<Task> tasksList2. I want to combine overlapping tasks (by breaking the tasks if needed, and adding actionItems from other tasks which are overlapping into a single new task object).

例如,假设我有一个名为T1的任务,从01/01/2015开始,结束于01/31/2015,其中包含操作项目A和B.然后用户创建一个新的任务T2,从2015年1月15日开始,结束于02/15/2015,并在其中添加了操作项目C.当我结合起来,我应该得到以下三个Task对象。

For example, assume I have a task called T1 that starts on 01/01/2015 and ends on 01/31/2015, which contains action items A and B. Then a user creates a new Task T2 that starts on 01/15/2015 and ends on 02/15/2015 and adds action item C into it. When I combine, I should get three Task objects as follows.


  • 任务X - 从01/01/2015到01/15/2015 ,包含操作项目A,B

  • 任务Y - 从2015年1月15日至2015年1月31日,包含项目A,B和C

  • 任务Z - 从01/31/2015到02/15/2015,包含项目C

为了可视化,如果我的任务两个列表中的对象在时间轴中如下所示:

To visualize, if my task object from the two lists look like the following in a timeline:

> [-----]      [-----]         [----]         [-----------------]
>     [-----]           [---------------]         [------]

然后,生成的任务列表将包含以下任务。

Then the resulting task list would contain tasks as follows.

> [--][-][--]  [-----]  [-----][----][--]      [-][------][-----]`

重叠的任务应该将actionItems从两个时间段重叠的任务组合起来其中它们重叠。

Overlapping tasks should have the actionItems combined from both of the tasks that overlap for the period in which they overlap.

最有效的方法是什么?目前我正在尝试与PeekableIterator不同的选择,但没有运气。任何使用JodaTime而不是Java 8 API的解决方案也是受欢迎的。

What is the most efficient way to handle this? At the moment I'm trying out different options with a PeekableIterator, but no luck yet. Any solutions using JodaTime instead of Java 8 APIs is also welcome.

推荐答案

首先,如果你只关心日期关于时间),最好使用 LocalDate 。其次,我假设你有一个任务构造函数。所以我使用以下任务对象:

First if you care about dates only (don't care about times), it's better to use LocalDate instead. Second, I assume that you have a task constructor. So I used the following Task object:

static class Task {
    LocalDate start;
    LocalDate end;
    Set<String> actionItems;

    public Task(LocalDate start, LocalDate end,
            Collection<String> actionItems) {
        this.start = start;
        this.end = end;
        this.actionItems = new HashSet<>(actionItems);
    }

    @Override
    public String toString() {
        return start + ".." + end + ": "+actionItems;
    }
}

这是一个更一般的任务的解决方案,根据您的规则,给定集合中的任务(输入集合不一定排序):

Here's the solution of more general task which just merges all the tasks in given collection according to your rules (the input collection is not necessarily sorted):

public static List<Task> convert(Collection<Task> input) {
    NavigableMap<LocalDate, Set<String>> map = new TreeMap<>();
    map.put(LocalDate.MIN, new HashSet<>());

    for (Task task : input) {
        if (!map.containsKey(task.start)) {
            map.put(task.start, new HashSet<>(map.lowerEntry(task.start).getValue()));
        }
        if (!map.containsKey(task.end)) {
            map.put(task.end, new HashSet<>(map.lowerEntry(task.end).getValue()));
        }
        for (Set<String> set : map.subMap(task.start, task.end).values()) {
            set.addAll(task.actionItems);
        }
    }
    List<Task> result = new ArrayList<>();
    LocalDate prev = null;
    Set<String> prevValues = Collections.emptySet();
    for (Entry<LocalDate, Set<String>> entry : map.entrySet()) {
        if (!prevValues.isEmpty()) {
            result.add(new Task(prev, entry.getKey(), prevValues));
        }
        prev = entry.getKey();
        prevValues = entry.getValue();
    }
    return result;
}

核心是 NavigableMap 其中每个键是下一个时间段的开始,该值是从给定开始到下一个键的时间段的动作集合(空值对应于没有动作的周期)。添加新任务后,现有条目将相应更新。使用示例:

The core thing is the NavigableMap where each key is the start of the next time period and the value is the collection of actions for the period from given start until the next key (empty values correspond to the periods without actions). Upon adding the new task existing entries are updated accordingly. Usage example:

List<Task> res = convert(Arrays.asList(
  new Task(LocalDate.parse("2015-01-01"), LocalDate.parse("2015-01-31"), 
        Arrays.asList("A", "B")),
  new Task(LocalDate.parse("2014-01-01"), LocalDate.parse("2014-01-31"), 
        Arrays.asList("A", "B")),
  new Task(LocalDate.parse("2015-01-15"), LocalDate.parse("2015-02-15"), 
        Arrays.asList("C"))));
res.stream().forEach(System.out::println);

输出:

2014-01-01..2014-01-31: [A, B]
2015-01-01..2015-01-15: [A, B]
2015-01-15..2015-01-31: [A, B, C]
2015-01-31..2015-02-15: [C]

这篇关于组合重叠日期范围 - Java的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆