user1107173 user1107173 - 5 months ago 9
Swift Question

Swift: Avoid imperative For Loop

What I'm trying to accomplish in imperative:

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)
}
}


What's the best way using a high order function or perhaps an array method (
array.filter
etc.) to compact the code above and also avoid using the
for
loop

Here is what I have tried, but the compiler gives an error:

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;
}
}

Answer

You need both filter() and map() :

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

The filter takes a predicate as an argument (which specifies which elements should be included in the result), and the map takes a transformation as an argument. You were trying to merge both aspects into the filter, which is not possible.

Update: As of Swift 2(?) has a flatMap() method for sequences, which can be used to obtain the result in a single step:

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

The closure is applied to all array elements, and the return value is an array with all non-nil unwrapped results.