使用 reduce() 在 Swift 中构建字典
Using reduce() to build a dictionary in Swift
我想使用函数式编程风格构建字典。我的 reduce() 似乎不起作用 - 我得到一个 "fatal error: unexpectedly found nil while unwrapping an Optional value"
func loadMoveToCalendarsRules(calendarIndex: Int) -> [String]? {
// return something like ["phone call", "buzz", "ring"]
return NSUserDefaults.standardUserDefaults().objectForKey(generateMoveToCalendarsRules_NSUserDefaultsKey(calendarIndex)) as? [String]
}
// Add indeces to an array of any type
func addIndices<T>(toArray: [T]) -> [(index: Int, value: T)] {
return Array(zip(toArray.indices, toArray))
}
typealias CalendarRules = [EKCalendar : [String]]?
func buildCalendarRules(cals: [EKCalendar]) -> CalendarRules {
let sortedCals = cals.sort { [=11=].title.lowercaseString < .title.lowercaseString }
// build move to cal rules.
let indexedCalList = addIndices(sortedCals)
// go through the sorted calendars and build a dictionary that associates each calendar with a string array. (These are keywords that apply to the given calendar.)
let calendarRules = indexedCalList.reduce(nil as CalendarRules) {
accumulator, nextValue in
var retVal: [EKCalendar : [String]]? = accumulator
// if there are values found in NSUserDefaults for this calendar index then retrieve them.
if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
retVal![nextValue.value] = rulesForCurrentCal // fatal error: unexpectedly found nil while unwrapping an Optional value
}
return retVal
}
print("------------ built calendar rules -------------")
print(Array(arrayLiteral: calendarRules?.keys))
print(Array(arrayLiteral: calendarRules?.values))
return calendarRules
}
您的 retVal
是可选的,并且以 nil
开始(您传入的初始值),但您正在使用 retVal!
强制展开它。您可以只使用 [:]
(一个空字典)作为初始值,然后 retVal
根本不需要是可选的。
您从 nil
开始,并且从未实例化 CalendarRules
字典,因此尝试使用 !
对其执行强制解包的尝试将会失败。相反,测试它是否是 nil
,如果是,则实例化一个。
在开始之前,我首先建议将日历规则定义为非可选类型。这样可以减少混乱:
typealias CalendarRules = [EKCalendar : [String]]
然后,您可以使用 nil
-合并运算符 ??
,在需要时实例化 CalendarRules
对象:
let calendarRules = indexedCalList.reduce(nil as CalendarRules?) { accumulator, nextValue in
if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
var retVal = accumulator ?? CalendarRules()
retVal[nextValue.value] = rulesForCurrentCal
return retVal
}
return accumulator
}
我觉得可能有更有效的方法,但这应该可以解决您的 "unexpectedly found nil" 错误。
我想使用函数式编程风格构建字典。我的 reduce() 似乎不起作用 - 我得到一个 "fatal error: unexpectedly found nil while unwrapping an Optional value"
func loadMoveToCalendarsRules(calendarIndex: Int) -> [String]? {
// return something like ["phone call", "buzz", "ring"]
return NSUserDefaults.standardUserDefaults().objectForKey(generateMoveToCalendarsRules_NSUserDefaultsKey(calendarIndex)) as? [String]
}
// Add indeces to an array of any type
func addIndices<T>(toArray: [T]) -> [(index: Int, value: T)] {
return Array(zip(toArray.indices, toArray))
}
typealias CalendarRules = [EKCalendar : [String]]?
func buildCalendarRules(cals: [EKCalendar]) -> CalendarRules {
let sortedCals = cals.sort { [=11=].title.lowercaseString < .title.lowercaseString }
// build move to cal rules.
let indexedCalList = addIndices(sortedCals)
// go through the sorted calendars and build a dictionary that associates each calendar with a string array. (These are keywords that apply to the given calendar.)
let calendarRules = indexedCalList.reduce(nil as CalendarRules) {
accumulator, nextValue in
var retVal: [EKCalendar : [String]]? = accumulator
// if there are values found in NSUserDefaults for this calendar index then retrieve them.
if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
retVal![nextValue.value] = rulesForCurrentCal // fatal error: unexpectedly found nil while unwrapping an Optional value
}
return retVal
}
print("------------ built calendar rules -------------")
print(Array(arrayLiteral: calendarRules?.keys))
print(Array(arrayLiteral: calendarRules?.values))
return calendarRules
}
您的 retVal
是可选的,并且以 nil
开始(您传入的初始值),但您正在使用 retVal!
强制展开它。您可以只使用 [:]
(一个空字典)作为初始值,然后 retVal
根本不需要是可选的。
您从 nil
开始,并且从未实例化 CalendarRules
字典,因此尝试使用 !
对其执行强制解包的尝试将会失败。相反,测试它是否是 nil
,如果是,则实例化一个。
在开始之前,我首先建议将日历规则定义为非可选类型。这样可以减少混乱:
typealias CalendarRules = [EKCalendar : [String]]
然后,您可以使用 nil
-合并运算符 ??
,在需要时实例化 CalendarRules
对象:
let calendarRules = indexedCalList.reduce(nil as CalendarRules?) { accumulator, nextValue in
if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
var retVal = accumulator ?? CalendarRules()
retVal[nextValue.value] = rulesForCurrentCal
return retVal
}
return accumulator
}
我觉得可能有更有效的方法,但这应该可以解决您的 "unexpectedly found nil" 错误。