如何在 ObservableList 中使用 LocalTime 添加缺失的时间?

How can I add the missing time using LocalTime in ObservableList?

我正在尝试创建一个日程安排,我只能在其中获取输入的时间和日程名称。

我想把时间表放在 List 但如果没有其他时间表,如果没有其他早期时间,列表应该添加一个从 6:00 AM 开始的新空时间表。

我有 ObservableList<DataClass>,它包含 LocalTime 和一些 String

示例 1: 假设列表包含 3 个项目:

[04:00 AM] [Some String]
[06:30 AM] [Some String]
[05:00 PM] [Some String]

我想将列表中缺少的时间从 4:00 AM 添加到 5:00 PM,因此列表将是:

[04:00 AM] [Some String]
[05:00 AM] [Some String]
[06:30 AM] [Some String]
[07:00 AM] [Some String]
[08:00 AM] [Some String]
[09:00 AM] [Some String]
[10:00 AM] [Some String]
[11:00 AM] [Some String]
[12:00 PM] [Some String]
[01:00 PM] [Some String]
[02:00 PM] [Some String]
[03:00 PM] [Some String]
[04:00 PM] [Some String]
[05:00 PM] [Some String]

示例 2: 假设列表包含 2 个项目:

[08:30 AM] [Some String]
[02:00 PM] [Some String]

我想将列表中缺少的时间从 6:00 AM 添加到 5:00 PM,因此列表将是:

[06:00 AM] [Some String]
[07:00 AM] [Some String]
[08:00 AM] [Some String]
[09:00 AM] [Some String]
[10:00 AM] [Some String]
[11:00 AM] [Some String]
[12:00 PM] [Some String]
[01:00 PM] [Some String]
[02:00 PM] [Some String]
[03:00 PM] [Some String]
[04:00 PM] [Some String]
[05:00 PM] [Some String]

示例 3: 假设列表包含 1 个项目:

[08:00 PM] [Some String]

我想将6:00 AM8:00 PM列表中缺失的时间补上,这样列表就可以了。

[06:00 AM] [Some String]
[07:00 AM] [Some String]
[08:00 AM] [Some String]
[09:00 AM] [Some String]
[10:00 AM] [Some String]
[11:00 AM] [Some String]
[12:00 PM] [Some String]
[01:00 PM] [Some String]
[02:00 PM] [Some String]
[03:00 PM] [Some String]
[04:00 PM] [Some String]
[05:00 PM] [Some String]
[06:00 PM] [Some String]
[07:00 PM] [Some String]
[08:00 PM] [Some String]

如果没有其他较早的时间,时间应该从06:00 AM开始,否则时间将从那个较早的时间开始。

如果没有其他时间,时间应该在5:00 PM结束,否则时间将在那个特定时间结束,我只想添加HOURincrement小时所以不应该有6:305:30,除非是手动输入的。

我正在考虑以下逻辑,但由于思路锁定无法继续。

  1. Sort the list base on the time from AM to PM to get the first time

  2. Check if the time of the first data is equal or less than 6:00 AM
    if true, then start from that time and continue adding the missing time until the 5:00 PM or the last time is reach.
    if false, then start from 6:00 AM and continue adding the missing time until the 5:00 PM or the last time is reach.

下面的代码是我目前所拥有的并且令人费解。

private void fillTheList(){
        ObservableList<DataClass> data = FXCollections.observableArrayList();
        Comparator<DataClass> comparator = Comparator.comparing(DataClass::getLocalTime);

        data.add(new DataClass(convertTime("05:00 PM"), "Sample Content"));
        data.add(new DataClass(convertTime("06:30 AM"), "Sample Content"));

        FXCollections.sort(data,comparator); //Sort the list from AM to PM

        for (DataClass list : data){
            if(list.getLocalTime().isBefore(LocalTime.of(6,0))){
                //The time is less than 6:00 AM then it should start here and Add the missing time but I don't know what to do next...
            }else{
                //the time is not less than 6:00 AM... I don't know what to do next..
            }
        }
        FXCollections.sort(data,comparator); //Sort the list from AM to PM again
}

private LocalTime convertTime(String timeString){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a");
        return LocalTime.parse(timeString, formatter);
}

PS:我实际上不确定我要问什么,所以如有必要,请随时提出修改建议。

更新:DataClass.class

public class DataClass {

    private LocalTime localTime;
    private String content;

    public DataClass(LocalTime localTime, String content){
        this.localTime = localTime;
        this.content = content;
    }

    public LocalTime getLocalTime(){
        return localTime;
    }

    public String getContent(){
        return content;
    }
}

您必须遵循这些步骤

  1. 获取开始的值,它将是06AM或列表的第一个值,这取决于哪个是第一个

  2. 得到end的值,就是第二个值

  3. 清除列表以删除开始值和结束值
  4. 遍历 2 之间的所有日期,每次递增 1 小时
  5. 结束条件是 i.isBefore(end.plusHours(1)) 而不是 i.isBefore(end) 因为您需要包含 end 元素
  6. 排序并打印
ObservableList<DataClass> data = FXCollections.observableArrayList();
Comparator<DataClass> comparator = Comparator.comparing(DataClass::getLocalTime);

data.add(new DataClass(convertTime("05:00 PM"), "Sample Content"));
data.add(new DataClass(convertTime("06:30 AM"), "Sample Content"));

FXCollections.sort(data,comparator); //Sort the list from AM to PM
// 1. & 2.
LocalTime begin = LocalTime.of(6,0);
if(data.get(0).getLocalTime().isBefore(begin)){
   begin = data.get(0).getLocalTime();
}

LocalTime end = LocalTime.of(17,0);
if(end.isBefore(data.get(data.size()-1).getLocalTime())){
    end = data.get(data.size()-1).getLocalTime();
}

// 3.
data.clear();
// 4. & 5.
for(LocalTime i = begin.withMinute(0); !i.isAfter(end); i = i.plusHours(1)){
   data.add(new DataClass(i, "Sample Content"));        
}

// 6. 
FXCollections.sort(data,comparator); //Sort the list from AM to PM again
System.out.println(data);
//  [06:00, 07:00, 08:00, 09:00, 10:00, 11:00, 12:00, 13:00, 14:00, 15:00, 16:00, 17:00]

不太确定您需要什么,但这可能是您需要的:

ObservableList<DataClass> data = FXCollections.observableArrayList();

// Need to specify the period that you want the entries to be filled
private void fill(LocalTime from, LocalTime to) {
    // Keep adding new entries until we have reached the end
    while (!from.isAfter(to)) {
        // We need a final variable for stream()
        final LocalTime temp = from;

        // If data does not contain any time that is equivalent to this time
        if (data.stream().noneMatch(d -> temp.equals(d.getLocalTime()))) {
            data.add(new DataClass(temp, "Hello World"));
        }

        // Increment the time by an hour, and wait for next loop cycle
        from = from.plusHours(1);
    }
}

除非您想以排序的方式显示数据,否则排序没有任何意义。

更新

此实现不会阻止您传递具有分钟(或秒)值的 fromto

如果需要纯小时单位,可以改成:

ObservableList<DataClass> data = FXCollections.observableArrayList();

// Need to specify the period that you want the entries to be filled
private void fill(int fromHour, int toHour) {
    LocalTime from = LocalTime.of(fromHour, 0);
    LocalTime to = LocalTime.of(toHour, 0);

    // Keep adding new entries until we have reached the end
    while (!from.isAfter(to)) {
        // We need a final variable for stream()
        final LocalTime temp = from;

        // If data does not contain any time that is equivalent to this time
        if (data.stream().noneMatch(d -> temp.equals(d.getLocalTime()))) {
            data.add(new DataClass(temp, "Hello World"));
        }

        // Increment the time by an hour, and wait for next loop cycle
        from = from.plusHours(1);
    }
}

这将强制两个边界值只有小时值。

进行如下操作

  1. 对列表进行排序
  2. 设置可能需要插入的时间(从插入范围的下界开始)
  3. 找到第一个时间>=要插入时间的元素的索引
  4. 如果元素的时间与要插入的时间不匹配,则在该索引处插入一个新元素
  5. 修改要插入的时间,如果没有离开插入范围则继续3.
ObservableList<DataClass> data = ...
LocalTime lowerBound = LocalTime.of(6, 0); // or some other input
LocalTime upperBound = LocalTime.of(12 + 5, 0); // or some other input


Comparator<DataClass> comparator = Comparator.comparing(DataClass::getLocalTime);
FXCollections.sort(data, comparator);

int size = data.size();
int index = 0;

while (!lowerBound.isAfter(upperBound)) {
    // find inserting index
    while (index < size && data.get(index).getLocalTime().isBefore(lowerBound)) {
        index++;
    }
    // insert, if not already in list
    if (index >= size || !data.get(index).getLocalTime().equals(lowerBound)) {
        data.add(index, new DataClass(lowerBound, "Inserted"));
        size++;
    }
    lowerBound = lowerBound.plusHours(1);
    index++;
}

请注意,对于列表中较小的步骤和较大数量的元素,代码的性能不是最理想的,因为添加到列表的中间在 O(n) 中运行,因此最终的复杂度将是 O(i + i*n + n*log(n)) 其中 i 是插入次数,n 是列表的初始大小。

为了改善这一点,您可以将所有新元素添加到列表的末尾,然后使用 mergesort 的合并步骤一次,这将导致运行时 O(i+n*log(n)):

final int size = data.size();
int index = 0;

while (!lowerBound.isAfter(upperBound)) {
    // find inserting index
    while (index < size && data.get(index).getLocalTime().isBefore(lowerBound)) {
        index++;
    }
    // insert, if not already in list
    if (index >= size || !data.get(index).getLocalTime().equals(lowerBound)) {
        data.add(new DataClass(lowerBound, "Inserted"));
    } else {
        index++;
    }
    lowerBound = lowerBound.plusHours(1);
}

// merge
DataClass[] merged = new DataClass[data.size()];
int insertionIndex = 0;
int index1 = 0;
int index2 = size;
while (index1 < size && index2 < merged.length) {
    DataClass v1 = data.get(index1);
    DataClass v2 = data.get(index2);
    if (v2.getLocalTime().isBefore(v1.getLocalTime())) {
        merged[insertionIndex] = v2;
        index2++;
    } else {
        merged[insertionIndex] = v1;
        index1++;
    }
    insertionIndex++;
}

// copy remaining
while (index1 < size) {
    merged[insertionIndex++] = data.get(index1++);
}
while (index2 < merged.length) {
    merged[insertionIndex++] = data.get(index2++);
}
data.setAll(merged);

你自己也很好。此外,azro 是正确的,您需要通过与数据中已有的最短时间和最长时间进行比较,找到要考虑插入的最短时间和最长时间。 Jai 是正确的,您应该在插入之前检查时间是否已经在列表中,并且流对于此目的很方便。我的版本使用 int 来迭代几个小时,但所有其他版本都是正确的,LocalTime 也有效。

    int minHour = 6;
    int maxHour = 17;
    if (! data.isEmpty()) {
        // adjust min and max from list contents
        int minExisintgHour = data.get(0).getLocalTime().getHour();
        if (minExisintgHour < minHour) {
            // if the list already contained 4:00 or 4:30,
            // we only need to add hours from 5, so add 1
            minHour = minExisintgHour + 1;
        }
        int maxExisintgHour = data.get(data.size() - 1).getLocalTime().getHour();
        if (maxExisintgHour > maxHour) {
            maxHour = maxExisintgHour;
        }
    }
    for (int hour = minHour; hour <= maxHour; hour++) {
        LocalTime time = LocalTime.of(hour, 0);
        boolean alreadyInData = data.stream().anyMatch(d -> d.getLocalTime().equals(time));
        if (! alreadyInData) {
            data.add(new DataClass(time, "Added beacuse time was missing"));
        }
    }

我假设您在问题中对上述代码前后的列表进行排序。如果您对最小值和最大值进行线性遍历(一些流也可以这样做),则可以省略之前的排序。

示例结果列表:

[06:00 AM] [Added beacuse time was missing]
[06:30 AM] [Sample Content]
[07:00 AM] [Added beacuse time was missing]
[08:00 AM] [Added beacuse time was missing]
[09:00 AM] [Added beacuse time was missing]
[10:00 AM] [Added beacuse time was missing]
[11:00 AM] [Added beacuse time was missing]
[12:00 PM] [Added beacuse time was missing]
[01:00 PM] [Added beacuse time was missing]
[02:00 PM] [Added beacuse time was missing]
[03:00 PM] [Added beacuse time was missing]
[04:00 PM] [Added beacuse time was missing]
[05:00 PM] [Sample Content]