如何在Swift中只求数组的一部分之和?
我目前正在尝试在Swift中构建我的第一个应用程序,并希望找到相对于当前月份的数组部分的总和。这是我的密码:如何在Swift中只求数组的一部分之和?,swift,Swift,我目前正在尝试在Swift中构建我的第一个应用程序,并希望找到相对于当前月份的数组部分的总和。这是我的密码: struct Hour { var date: String? var time: String? init(date: String?, time: String?) { self.date = date self.time = time } } let hoursData = [ Hour(date: "N
struct Hour {
var date: String?
var time: String?
init(date: String?, time: String?) {
self.date = date
self.time = time
}
}
let hoursData = [
Hour(date: "Nov 29, 2015", time: "7"),
Hour(date: "Dec 12, 2015", time: "7"),
Hour(date: "Dec 14, 2015", time: "7"),
Hour(date: "Dec 25, 2015", time: "7") ]
我想知道如何制作一个包含当前月份
时间
数据总和的变量?或者任何一个月?非常感谢你们提供的任何帮助。你们也可以从功能上提供帮助
let sum = hoursData
.filter { $0.date?.hasPrefix("Dec") ?? false } // Only get dates in the correct month
.flatMap { $0.time } // Map to an array of non nil times
.flatMap { Int($0) } // Convert strings to ints
.reduce(0) { $0 + $1 } // Sum up the times
如果存储非可选的
int
而不是可选的字符串
,那么这会简单得多。或者您可以只使用NSDateComponents
首先,我要稍微重写一下您的结构,这两个属性都可以是不可变的 我使用NSDate代替日期字符串,持续时间使用double
struct Hour {
let date: NSDate
let duration: Double
init(date: NSDate, duration: Double) {
self.date = date
self.duration = duration
}
}
我创造了这样的时间
let hoursData = [
Hour(date: { let c = NSDateComponents(); c.day = 29; c.month = 11; c.year = 2015; return NSCalendar.currentCalendar().dateFromComponents(c)!}(), duration: 7),
Hour(date: { let c = NSDateComponents(); c.day = 12; c.month = 12; c.year = 2015; return NSCalendar.currentCalendar().dateFromComponents(c)!}(), duration: 7),
Hour(date: { let c = NSDateComponents(); c.day = 14; c.month = 12; c.year = 2015; return NSCalendar.currentCalendar().dateFromComponents(c)!}(), duration: 7),
Hour(date: { let c = NSDateComponents(); c.day = 15; c.month = 12; c.year = 2015; return NSCalendar.currentCalendar().dateFromComponents(c)!}(), duration: 7)]
如果您想知道这种语法:我使用隐式未命名闭包来创建NSDate参数
现在,我过滤月份和年份,并使用reduce
方法汇总过滤对象
let today = NSDate()
let totalDuration = hoursData.filter{
let objectsComps = NSCalendar.currentCalendar().components([.Month, .Year], fromDate: $0.date)
let todaysComps = NSCalendar.currentCalendar().components([.Month, .Year], fromDate: today)
return objectsComps.month == todaysComps.month && objectsComps.year == todaysComps.year
}.reduce(0) { (duration, hour) -> Double in
duration + hour.duration
}
虽然这是一个很好的答案,但我想指出Rob的答案有一个小缺陷:struct
Hour
隐藏了日期字符串需要采用某种格式的依赖关系。这违反了,中的D。但这很容易解决
创建Hour
实例时,只需传入日期格式化程序
struct Hour {
let date: NSDate
let duration: Double
init(date: NSDate, duration: Double) {
self.date = date
self.duration = duration
}
init (dateFormatter:NSDateFormatter, dateString:String, duration:Double) {
self.init(date: dateFormatter.dateFromString(dateString)!, duration:duration)
}
}
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MMM d, y"
let hoursData = [
Hour(dateFormatter: dateFormatter, dateString: "Nov 29, 2015", duration: 7),
Hour(dateFormatter: dateFormatter, dateString: "Dec 12, 2015", duration: 7),
Hour(dateFormatter: dateFormatter, dateString: "Dec 14, 2015", duration: 7),
Hour(dateFormatter: dateFormatter, dateString: "Dec 25, 2015", duration: 7),
Hour(dateFormatter: dateFormatter, dateString: "Dec 25, 2017", duration: 7)
]
现在,使用Hour
的用户可以根据需要定义格式,这对本地化应用可能会有所帮助
过滤和还原保持不变
但现在我们有一个新问题:
NSDateformatter的
dateFromString()
可能返回nil。目前我们使用强制展开它代码>,但这在生产应用程序中可能不好
我们应该允许适当的错误处理,允许便利init抛出错误
enum HourError: ErrorType {
case InvalidDate
}
struct Hour {
let date: NSDate
let duration: Double
init(date: NSDate, duration: Double) {
self.date = date
self.duration = duration
}
init (dateFormatter:NSDateFormatter, dateString:String, duration:Double) throws {
let date = dateFormatter.dateFromString(dateString)
guard date != nil else { throw HourError.InvalidDate}
self.init(date: date!, duration:duration)
}
}
如果我们像这样使用它
do {
let now = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MMM d, y"
let hoursData = [
try Hour(dateFormatter: dateFormatter, dateString: "Nov 29, 2015", duration: 7),
try Hour(dateFormatter: dateFormatter, dateString: "Dec 12, 2015", duration: 7),
try Hour(dateFormatter: dateFormatter, dateString: "Dec 14, 2015", duration: 7),
try Hour(dateFormatter: dateFormatter, dateString: "Dec 25, 2015", duration: 7),
/*⛈*/ try Hour(dateFormatter: dateFormatter, dateString: " 25, 2017", duration: 7)
]
let totalDuration = hoursData.filter{
let objectsComps = NSCalendar.currentCalendar().components([.Month, .Year], fromDate: $0.date)
let todaysComps = NSCalendar.currentCalendar().components([.Month, .Year], fromDate: now)
return objectsComps.month == todaysComps.month && objectsComps.year == todaysComps.year
}.reduce(0) {
$0 + $1.duration
}
print(totalDuration)
} catch HourError.InvalidDate{
print("one or more datestrings must be wrong")
}
错误将被捕获
我可能会这样做:
// get prefix for current month
let formatter = NSDateFormatter()
formatter.dateFormat = "MMM"
let monthString = formatter.stringFromDate(NSDate())
// now add up the time values for that month
let results = hoursData.filter { $0.date?.hasPrefix(monthString) ?? false }
.reduce(0) { $0 + (Int($1.time ?? "0") ?? 0) }
或者,如果您也想为年份添加支票:
let formatter = NSDateFormatter()
formatter.dateFormat = "MMM"
let monthString = formatter.stringFromDate(NSDate())
formatter.dateFormat = "yyyy"
let yearString = formatter.stringFromDate(NSDate())
let results = hoursData.filter { $0.date?.hasPrefix(monthString) ?? false && $0.date?.hasSuffix(yearString) ?? false }
.reduce(0) { $0 + (Int($1.time ?? "0") ?? 0) }
print(results)
注意,在上述两种情况下,由于您使用的是optionals,因此我使用??
来处理值为nil
(以及时间中是否存在非数字字符串)
就个人而言,我建议Hour
使用NSDate
和Float
而不是String
,除非你真的需要,否则不要使用选项,使用let
而不是var
:
struct Hour {
let date: NSDate
let time: Float
init(dateString: String, time: Float) {
let formatter = NSDateFormatter()
formatter.dateFormat = "MMM, d, y"
self.date = formatter.dateFromString(dateString)!
self.time = time
}
}
然后代码变成:
let hoursData = [
Hour(dateString: "Nov 29, 2015", time: 7),
Hour(dateString: "Dec 12, 2015", time: 7),
Hour(dateString: "Dec 14, 2015", time: 7),
Hour(dateString: "Dec 25, 2015", time: 7),
Hour(dateString: "Dec 25, 2017", time: 7)
]
let calendar = NSCalendar.currentCalendar()
let currentComponents = calendar.components([.Month, .Year], fromDate: NSDate())
let results = hoursData.filter {
let components = calendar.components([.Month, .Year], fromDate: $0.date)
return components.month == currentComponents.month && components.year == currentComponents.year
}.reduce(0) { return $0 + $1.time }
print(results)
还可以进行进一步的优化(例如,不重复实例化NSDateFormatter
),但这说明了使用NSDate
对象可以使用日历计算,而不是查找子字符串。什么是参数时间?时间点?持续时间?为什么它是字符串而不是数字类型?对于日期,您应该使用NSDate或NSDateComponents对象。Viking提出了一个很好的观点,通常尝试创建自己的日期结构是一个坏主意(TM)。如果要使用某个日期单位,请使用NSDateComponents。@vikingosegundo参数“时间”是一小时,比如说7小时。这在我脑子里是有道理的哈哈,对不起我没有解释清楚。它们都是字符串,因为它们是由用户输入并放入表中的。正如我所说,我是新手,所以这似乎是最好的方法。但是,日期是使用NSDate输入的。您应该将用户的输入转换为可使用的最佳类型。如果字符串参数始终包含数字字符串,请将其设置为数字参数!约会也一样。这真的很棒,非常适合我要找的东西!但是我遇到了一些问题,我使用结果作为UILabel的数据,但是当我向数组添加数据时(通过添加小时数屏幕),标签不会更新。你能为我指出正确的方向吗?你可以做一些类似于self.label.text=“\(结果)”
。您可能需要执行类似于self.label.text=“total=\(results)”
的操作,然后查看字符串的total=
部分是否也显示出来。这就把它缩小到标签的一些问题,而不是计算结果的一些问题。如果您是从后台线程(例如,从NSURLSession
任务的完成处理程序中)执行此操作,请记住将其分派到主队列,例如dispatch\u async(dispatch\u get\u main\u queue()){self.label.text=“total=\(results)}
@IsaacPevy-如果您在成功计算总数后更新标签时仍然遇到问题(例如,您已经打印了总数,这很好),那么在标签更新过程中发布问题,重点是向我们展示的不是上述计算内容,而是标签更新内容。