基于NSDate将数组映射到字典

时间:2015-10-02 01:58:38

标签: ios arrays swift2

希望根据该对象的date属性找出一种更清晰的Swifty方法来将对象数组转换为dictionay。 仅关注日期,即2015年12月31日 - 没有时间比较。

所以,如果很多事情有5件事都有2015年12月31日的日期,那么这个词。将有一个项目日期和与该数据相关联的5个事物的数组。

例如

   struct Thing {
        var name:String
        var date:NSDate
    }

    let manyThings = [Thing]()

目前我使用String作为词典,让它有效。键。但肯定有很好的快速方法可以做到这一点。

func dateGroup(things:[Thing]) -> [String:[Thing]] {

    var sameDays = [String:[Thing]]()

    // sort into Dates, using local date string as filter
    let dateFormatter = NSDateFormatter()
    dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle
    dateFormatter.dateStyle = NSDateFormatterStyle.LongStyle
    dateFormatter.timeZone = NSTimeZone()

    for aThing in things {

        let localDate = dateFormatter.stringFromDate(aThing.date)

        if var thingsForDay = sameDays[localDate] {
            thingsForDay.append(aThing)
            sameDays[localDate] = thingsForDay
        }
        else {
            var empty = [Thing]()
            empty.append(aThing)
            sameDays[localDate] = empty
        }
    }
}

2 个答案:

答案 0 :(得分:2)

您可以使用数组上的reduce函数将其转换为Dictionary。这可以说更像是一种功能性方法,可能使其成为一种不错的Swift方式。

func dateGroup(things:[Thing]) -> [String:[Thing]] {
    // sort into Dates, using local date string as filter
    let dateFormatter = NSDateFormatter()
    dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle
    dateFormatter.dateStyle = NSDateFormatterStyle.LongStyle
    dateFormatter.timeZone = NSTimeZone()

    return things.reduce([:]) { (reduction, aThing) -> [String:[Thing]] in
        let localDate = dateFormatter.stringFromDate(aThing.date)

        var result = reduction
        if var thingsForDay = result[localDate] {
            thingsForDay.append(aThing)
            result[localDate] = thingsForDay
        }
        else {
            result[localDate] = [aThing]
        }

        return result
    }
}

仅供参考。 Swift中的大多数集合中有一些方法我认为是在这个阵营中。有filter()map()reduce()filter()的使用是相当明显的,它基于一些返回Bool的闭包为您提供了一个集合的子集。 map()函数用于将集合转换为另一个集合,其中每个元素都转换为其他元素。 reduce()函数用于将某些集合转换为某些结果(在这种情况下,该结果是原始集合的子Dictionary的{​​{1}}。

答案 1 :(得分:1)

我还使用了reduce,另外,我使用??运算符来清理if条件。

func dateGroup(things:[Thing]) -> [String:[Thing]] {
    // sort into Dates, using local date string as filter
    let dateFormatter = NSDateFormatter()
    dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle
    dateFormatter.dateStyle = NSDateFormatterStyle.LongStyle
    dateFormatter.timeZone = NSTimeZone()

    return things.reduce([:]) {
        (var sameDays, aThing) in

        let date = dateFormatter.stringFromDate(aThing.date)

        sameDays[date] = (sameDays[date] ?? []) + [aThing]

        return sameDays
    }
}

适用于iOS 7及以下版本

func dateByRemovingTimeFromDate(date: NSDate) -> NSDate {
    let calendar = NSCalendar.currentCalendar()
    let components = calendar.components([.Year, .Month, .Day], fromDate: date)

    return calendar.dateFromComponents(components)!
}

func dateGroup(things:[Thing]) -> [NSDate:[Thing]] {

    return things.reduce([:]) {
        (var sameDays, aThing) in

        let date = dateByRemovingTimeFromDate(aThing.date)

        sameDays[date] = (sameDays[date] ?? []) + [aThing]

        return sameDays
    }
}

对于iOS 8及以上版本dateByRemovingTimeFromDate可以简化

func dateByRemovingTimeFromDate(date: NSDate) -> NSDate {
    return NSCalendar.currentCalendar().dateBySettingHour(0, minute: 0, second: 0, ofDate: date, options: [])!
}