arrays - 如何比较数组中的时间?

标签 arrays swift date datetime swift4

我正在构建一个公交车到达时间应用程序。它需要一个向其传递两个参数的函数:用户所在的当前站点和用户想要前往的目的地站点。到达时间是硬编码的,并且没有任何类型的“实时到达”时间。

我遇到的问题是尝试比较时间并计算出下一类车何时到达。时间存储在数组中并且无法更改。

例如,如果数组如下:["08:00", "23:00", "01:00", "04:00"] 另外,假设当前时间是“16:00”,函数返回的时间是“23:00”。很简单,对吧?我已经使用扩展类对这一点进行了编码,可以在我的 Pastebin 中找到该扩展类。

但是,当时间进入“第二天”时,问题就出现了,所以如果时间是“00:00”,我不知道如何返回“01:00”,因为我的函数只会返回数组中的第一次(“08:00”),因为“00:00”低于“08:00”。

import UIKit

// Replace the variable currentTime with a value of "00:00" and see how my function returns "08:17" which is wrong. I want the function to return "00:03" since it is the next time in the array. Or if the current time is "01:00" it should return "01:03". BUT, if the current time is "01:04" or greater, it should return the first time in the array "08:17"

// Hard coded bus arrival times
let array: [String] = ["08:17", "08:37", "08:57", "09:21", "09:51", "10:21", "10:51", "11:21", "11:51", "12:21", "12:51", "13:21", "13:51", "14:21", "14:51", "15:21", "15:51", "16:21", "16:51", "17:21", "17:51", "18:21", "18:51", "19:21", "19:51", "21:03", "22:03", "23:03", "00:03", "01:03"]

// Date object stuff
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let date = Date()
let calender = Calendar.current
let components = calender.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
let year = components.year
let month = components.month
let day = components.day
let hour = components.hour
let minute = components.minute
let second = components.second

// Returns current time in a "HH:mm:ss" format
func getTimeString() -> String {
    var minuteAsString = String(minute!)

    if minute! < 10 {
        minuteAsString = "0\(String(minute!))"
    }

    let timeString = String(hour!) + ":" + minuteAsString
    return timeString
}

func getNextBus(_ currentStop: String,_ destinationStop: String) -> String {
    var listToUse: [String] = []
    let currentTime = getTimeString()
    print(currentTime)

    switch (currentStop, destinationStop) {
    case ("stop1", "stop2"):
        listToUse = array
    default: ()
    }
    print(listToUse)

    for busTime in listToUse {
        if currentTime < busTime {
            return busTime
        }
    }
    return "Error! No time found."
}

print(getNextBus("stop1", "stop2"))

// Time class which allows times to be compared and equated
class Time: Comparable, Equatable {
    init(_ date: Date) {
        //get the current calender
        let calendar = Calendar.current

        //get just the minute and the hour of the day passed to it
        let dateComponents = calendar.dateComponents([.hour, .minute], from: date)

        //calculate the seconds since the beggining of the day for comparisions
        let dateSeconds = dateComponents.hour! * 3600 + dateComponents.minute! * 60

        //set the varibles
        secondsSinceBeginningOfDay = dateSeconds
        hour = dateComponents.hour!
        minute = dateComponents.minute!
    }

    init(_ hour: Int, _ minute: Int) {
        //calculate the seconds since the beggining of the day for comparisions
        let dateSeconds = (hour * 3600 + minute * 60)

        //set the variables
        secondsSinceBeginningOfDay = dateSeconds
        self.hour = hour
        self.minute = minute
    }

    var hour : Int
    var minute: Int

    var date: Date {
        //get the current calender
        let calendar = Calendar.current

        //create a new date components.
        var dateComponents = DateComponents()

        dateComponents.hour = hour
        dateComponents.minute = minute

        return calendar.date(byAdding: dateComponents, to: Date())!
    }

    /// the number or seconds since the beginning of the day, this is used for comparisions
    public let secondsSinceBeginningOfDay: Int


    static func < (lhs: Time, rhs: Time) -> Bool {
        return lhs.secondsSinceBeginningOfDay < rhs.secondsSinceBeginningOfDay
    }

}```

最佳答案

假设我们有这个数组:

let array = ["08:00", "23:00", "01:00", "04:00"]

处理“总线时间”的更方便的方法是定义一个如下所示的结构:

struct BusTime: Comparable, CustomStringConvertible {
    let hour    : Int
    let minute  : Int

    static func < (lhs: BusTime, rhs: BusTime) -> Bool {
        return (lhs.hour, lhs.minute) < (rhs.hour, rhs.minute)
    }

    var description: String {
        get {
            let formatter = NumberFormatter()
            formatter.minimumIntegerDigits = 2
            return formatter.string(for: hour)! + ":" + formatter.string(for: minute)!
        }
    }
}

注意:在答案的其余部分中,为了简洁起见,我将强制展开)

让我们创建一个 BusTime 的排序数组:

let busTimes: [BusTime] = array.map { str in
    return BusTime(hour: Int(str.prefix(2))!, minute: Int(str.suffix(2))!)
}
var sortedBusTimes = busTimes.sorted()

我们还定义一个变量nextBus,它表示下一类车时间:

var nextBus: BusTime = sortedBusTimes[0]

现在,让我们创建一个与当前日期相对应的时间:

let nowComps = Calendar.current.dateComponents([.hour, .minute], from: Date())
let now = BusTime(hour: nowComps.hour!, minute: nowComps.minute!)

通过二分查找,我们将能够在 O(log(n)) 中找到下一类车时间:

var low  = sortedBusTimes.startIndex
var high = sortedBusTimes.endIndex

while low < high {
    let middle = low + (high - low)/2      
    let middleTime = sortedBusTimes[middle]
    if middleTime == now {
        low = middle
        break
    } else if middleTime < now {
        low = middle + 1
    } else if now < middleTime {
        high = middle
    }
}

if low != sortedBusTimes.endIndex, high != 0 {
    nextBus = sortedBusTimes[low]
}

定义middle可以这样更简单:

let middle = low + (high - low)/2

但是拿this文章考虑在内。

最后,让我们检查一下:

print(nextBus)

撰写此答案时,时间为 17:52。所以控制台打印的结果是:

23:00

关于arrays - 如何比较数组中的时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57576582/

相关文章:

python - 在 Python 中,如何在排序的日期列表中查找特定日期之间的位置?

c++ - 在 C++ 中使用分隔符获取输入

java - 有没有更有效的方法在ArrayList和Array之间进行转换

swift - 计分系统多次计分

swift - Vapor:git push heroku master 失败

php - 如何从完整的 'Day' 字符串中仅提取 'Date' 值?

java - 使用二维数组乘以表

python - 多维ndarray集合运算

ios - 将 Core Data 对象从 tableViewController 传递到 TabBarController

JavaScript 帮助 - 比较 (dd/MMM/yyyy) 格式的两个日期