Swift:避免使用For Loop

时间:2015-05-19 20:59:12

标签: swift ios8 functional-programming

我正在努力完成的任务:

var mapNames = [String]()
var mapLocation = [String]()

for valueMap in valueMaps {
    if let name = valueMap.name {
         mapNames.append(name)
    }
    if let location = valueMap.location {
        mapLocation.append(location)
    }
}

使用高阶函数或数组方法(array.filter等)的最佳方法是压缩上面的代码并避免使用for循环

这是我尝试过的,但编译器给出了一个错误:

let getArrayOfNames = valueMaps.filter() {
    if let name = ($0 as valueMaps).name as [String]! {
        return name;
    }
}

let getArrayOfLocations = valueMaps.filter() {
    if let type = ($0 as valueMaps).location as [String]! {
        return type;
    }
}

2 个答案:

答案 0 :(得分:5)

您需要filter()map()

let mapNames = valueMaps.filter( {$0.name != nil }).map( { $0.name! })
let mapLocations = valueMaps.filter( {$0.location != nil }).map( { $0.location! })

过滤器将谓词作为参数(指定哪个 元素应该包含在结果中),并且地图需要 转换作为参数。你试图合并两者 进入过滤器的方面,这是不可能的。

更新:从Swift 2(?)开始,序列有flatMap()个方法, 可以用来一步获得结果:

let mapNames = valueMaps.flatMap { $0.name }

闭包应用于所有数组元素,返回值为 包含所有非零未打包结果的数组。

答案 1 :(得分:2)

filter()函数需要其闭包来返回bool - 而不是要存储在数组中的值。您可以将过滤器和地图链接在一起以获得您想要的内容,然后:

let getArrayOfNames = valueMaps
    .filter { $0.name != nil }
    .map{ $0.name! }

或者,使用reduce:

在一个函数中执行此操作
let getArrayOfNames = valueMaps
    .reduce([String]()) {
        accu, element in
        if let name = element.name {
            return accu + [name]
        } else {
            return accu
        }
}

实际上,降低可能会更好一点:

let getArrayOfNames = valueMaps.reduce([String]()) {
  (names, value) in names + (value.name.map{[$0]} ?? [])
}

let getArrayOfLocations = valueMaps.reduce([String]()) {
  (locs, value) in locs + (value.location.map{[$0]} ?? [])
}