如何在Swift中只得到数组的一部分?

时间:2015-12-22 23:02:44

标签: swift

我目前正在尝试在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") ] 数据总和的变量?或者任何一个月的事情?你们给予的任何帮助都会非常感激。

3 个答案:

答案 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")
}

错误将被捕获。

full code

答案 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使用NSDateFloat而不是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对象可以让您使用日历计算,而不是查找子字符串。