在Swift 5中,如何有效地提取和使用多维数组中的元素



编程新手这是我使用swift/xcode的第5天,请耐心等待。

我已经创建了一个格式为-[[A],[B],[C],[D],[E],[F]]的数组。。。用作查找表。要求获取A-AM/PM和B,C-开始时间,并检查当前时间(小时、分钟(是否在D,E-结束时间息F

例如,如果现在是凌晨3点04分,我的程序将使用下表打印"睡觉,我会告诉你什么时候是4">

// [[A], [B], [C], [D], [E], [F]], ...

let messageArray : Array = [
[["AM"], [00], [00], [00], [01], ["it's nmidnight"]],
[["AM"], [00], [02], [02], [59], ["it's very late (or early), nto be up"]],
[["AM"], [03], [00], [03], [01], ["are you ready nfor the 03 am call?"]],
[["AM"], [03], [02], [03], [59], ["go to sleep ni'll let you know when it's n4"]],...

我知道如何从当前时间开始计算小时和分钟。

let date = Date()
var calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)

我需要一个内外循环来遍历矩阵的每个x,y。对于每个单元格,我需要提取数组,并获取前4个元素——AM/PM、startHour、startMinute、endHour、endMinute,以检查当前小时、分钟是否在这些范围内;但我不确定我是否理解多维数组解析。我试过各种各样的方法,也试过上网查找,但都很吃力。

我应该使用数组吗?还有其他更有效的数据结构吗?

如有任何帮助或建议,我们将不胜感激。

谢谢,

您可以创建自己的结构,如下所示:

enum AmPm {
case am, pm
}
struct TimeMessage {
var ampm: AmPm
var hourStart: Int
var minuteStart: Int
var hourEnd: Int
var minuteEnd: Int
var message: String
}

具有一些方便的方法和特性:

extension TimeMessage {
init(_ ampm: AmPm, _ hourStart: Int, _ minuteStart: Int, _ hourEnd: Int, _  minuteEnd: Int, _ message: String) {
self.ampm = ampm
self.hourStart = hourStart
self.minuteStart = minuteStart
self.hourEnd = hourEnd
self.minuteEnd = minuteEnd
self.message = message
}
}
extension TimeMessage {
var hourStart24: Int {
switch ampm {
case .am:
return hourStart
case .pm:
return hourStart + 12
}
}
var hourEnd24: Int {
switch ampm {
case .am:
return hourEnd
case .pm:
return hourEnd + 12
}
}
}
extension TimeMessage {
func matches(_ date: Date) -> Bool {
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
return (hourStart24, minuteStart) <= (hour, minute)
&& (hour, minute) <= (hourEnd24, minuteEnd)
}
}

使用上面的结构,您可以将messageArray声明为:

let messageArray: [TimeMessage] = [
TimeMessage(.am, 00, 00, 00, 01, "it's nmidnight"),
TimeMessage(.am, 00, 02, 02, 59, "it's very late (or early), nto be up"),
TimeMessage(.am, 03, 00, 03, 01, "are you ready nfor the 03 am call?"),
TimeMessage(.am, 03, 02, 03, 59, "go to sleep ni'll let you know when it's n4"),
//...
]

并将其用作:

let now = Date()
if let timeMessage = messageArray.first(where: {$0.matches(now)}) {
print(timeMessage.message)
} else {
print("No match")
}

使用[(小时,分钟(:字符串]类型的字典

let hour = Calendar.current.component(.hour, from: Date())
let minute = Calendar.current.component(.minute, from: Date())
let messageArray: [(Int, Int):String] = [
(0, 1): ["it'snmidnight"],
(2, 59): ["it'svery early"],
(3, 01): ["that 3am call?"],
(3, 59): ["come back at 4"]
]

然后您可以使用函数编程来检查订单。

extension Dictionary where Key == (Int, Int) {
func smallestValue<T: Value>(_ time: (Int, Int)) -> T? {
let message: T? = nil
for i in self {
// Check for smallest case that is good
}
return message
}
}
let message = messageArray.smallestValue((hour, minute)) ?? "Good job for being awake"
print(message)

可能需要为(Int,Int(创建一个结构

这有点棘手,因为Date同时为日期和时间建模,并且没有只为时间或日期建模的对应对象。我即兴使用了一组整数。这可能不是最好的解决方案,但这是我能想到的最好的(欢迎建议!(

我会使用一个结构来为每条消息建模(包括它的startTimeendTime和一个计算属性,该属性允许您为它派生一个DateInterval

我还会制作一个TimedMessageList,它存储将DateIntervals与Messages关联起来的查找表。由于查找涉及检查间隔,而不是精确匹配,所以Dictionary对我们没有真正的帮助,所以我只使用元组数组,每次查找都对它们进行线性搜索。

如果性能出现问题,您可以探索基于树的数据结构,如区间树。尽管这增加了很多复杂性,而且可能实际上比线性搜索慢,直到你开始需要查找数千个或更多的条目。

结构在这里更合适:

import Foundation
struct Message {
let startTime: (h: Int, m: Int)
let endTime: (h: Int, m: Int)
let message: String
var applicableTimeIntererval: DateInterval { 
let calendar = Calendar.current
let now = Date()
return DateInterval(
start: calendar.date(bySettingHour: startTime.h, minute: startTime.m, second: 0, of: now)!, // TODO: are these safe to force unwrap?
end:   calendar.date(bySettingHour:   endTime.h, minute:   endTime.m, second: 0, of: now)!  // TODO: are these safe to force unwrap?
)
}
}
struct TimedMessageList {
let messagesByTimeInterval: [(dateInterval: DateInterval, message: Message)]
init(_ messages: [Message]) {
self.messagesByTimeInterval = messages.map { msg in (msg.applicableTimeIntererval, msg) }
}
func lookUpMessage(forTime timeTuple: (h: Int, m: Int)) -> Message? {
let time = Calendar.current.date(bySettingHour: timeTuple.h, minute: timeTuple.m, second: 0, of: Date())! // TODO: are these safe to force unwrap?
return self.messagesByTimeInterval.first(where: { (timeInterval: DateInterval, msg: Message) -> Bool in
timeInterval.contains(time)
})?.message
}
}
let messages = TimedMessageList([
Message(startTime: (h: 00, m: 00), endTime: (h: 00, m: 01), message: """
it's 
midnight
"""),
Message(startTime: (h: 00, m: 02), endTime: (h: 02, m: 59), message: """
it's very late (or early), 
to be up
"""),
Message(startTime: (h: 03, m: 00), endTime: (h: 03, m: 01), message: """
are you ready 
for the 03 am call?
"""),
Message(startTime: (h: 03, m: 02), endTime: (h: 03, m: 59), message: """
go to sleep  
i'll let you know when it's 
4
"""),
])
let messageFor0305 = messages.lookUpMessage(forTime: (h: 03, m: 05))
if let messageFor0305 = messageFor0305 {
print(messageFor0305.message)
} else {
print("There is no message for 3:05")
}

这是ClosedRange的一个很酷的答案。它允许您创建自定义的时间范围,并且可以根据您选择的时间向您提供多条消息。

struct Time { var hour: Int, min: Int }
extension Time: Comparable, Hashable {
static func < (lhs: Time, rhs: Time) -> Bool {
return lhs.hour < rhs.hour || (lhs.hour == rhs.hour && lhs.min < rhs.min)
}
init(_ h: Int,_ m: Int) { hour = h; min = m }
}
extension Dictionary where Key == ClosedRange<Time> {
func has(_ time: Time) -> [Value] {
var messages = [Value]()
for i in self {
time >= i.key.lowerBound && time <= i.key.upperBound ? { messages.append(i.value) }() : {}()
}
return messages
}
}
let a = [
Time(0, 0)...Time(0, 1): "it's midnight",
Time(0, 2)...Time(2, 59): "it's very early",
Time(3, 0)...Time(3, 1): "that 3am call?",
Time(3, 2)...Time(3,59): "come back at 4",
Time(3, 50)...Time(3, 59): "almost 4"
]
a.has(Time(3, 58))
// returns ["come back at 4", "almost 4"]

最新更新