我目前正在尝试在Swift中构建我的第一个应用程序,并且我希望找到相对于当前月份的数组部分的总和。这是我的代码:
{
"scripts": {
"test": "NODE_PATH=./src mocha ./src/**/test/spec.js --compilers js:babel-core/register --recursive"
}
}
我想知道如何制作一个包含当月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") ]
数据总和的变量?或者任何一个月的事情?你们给予的任何帮助都会非常感激。
答案 0 :(得分:2)
首先我会稍微改写你的结构,
这两个属性都是不可变的。
我使用NSDate而不是字符串表示日期,而是使用双倍的持续时间
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
隐藏了日期字符串需要具有某种格式的依赖关系。这违反了Dependency Inversion Principle中的SOLID Principles, 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's
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")
}
错误将被捕获。
答案 1 :(得分:0)
您也可以在功能上执行此操作
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
如果您存储非可选Ints
而不是可选Strings
,这可能会简单得多。或者您可以使用NSDateComponents
。
答案 2 :(得分:0)
我可能会这样做:
// 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)
请注意,在上述两个方面,由于您使用了选项,我使用??
来处理值nil
时(以及是否有time
)中的非数字字符串。
就我个人而言,我建议Hour
使用NSDate
和Float
而不是String
,除非您真的需要,否则不要使用选项,并使用{{ 1}}代替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
对象可以让您使用日历计算,而不是查找子字符串。