18

Say I had the below api :

func paths() -> [String?] {
    return ["test", nil, "Two"]
}

And I was using this in a method where I needed [String], hence I had to unwrap it using the simple map function. I'm currently doing :

func cleanPaths() -> [String] {
    return paths.map({$0 as! String})
}

Here, the force-cast will cause an error. So technically I need to unwrap the Strings in the paths array. I'm having some trouble doing this and seem to be getting silly errors. Can someone help me out here?

gran_profaci
  • 8,087
  • 15
  • 66
  • 99

4 Answers4

46

compactMap() can do this for you in one step:

let paths:[String?] = ["test", nil, "Two"]

let nonOptionals = paths.compactMap{$0}

nonOptionals will now be a String array containing ["test", "Two"].

Previously flatMap() was the proper solution, but has been deprecated for this purpose in Swift 4.1

Allen
  • 219
  • 2
  • 12
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • Kudos for digging this function from the trench of Swift's undocumented higher-order functions! – Code Different Jun 30 '15 at 21:27
  • 1
    @ZoffDino - Credit for this should belong to Airspeed Velocity: http://airspeedvelocity.net/2015/06/23/protocol-extensions-and-the-death-of-the-pipe-forward-operator/ who first pointed this out to me. – Brad Larson Jun 30 '15 at 21:29
  • I've been playing with Swift for 9 months and still couldn't find a complete list of higher order functions in the language. Apple has a lot to catch up on this front. – Code Different Jun 30 '15 at 21:30
  • [Optional `map()` here](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Optional_Enumeration/index.html#//apple_ref/doc/uid/TP40015225-CH1-DontLinkElementID_8), [Sequence here](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_SequenceType_Protocol/index.html#//apple_ref/doc/uid/TP40015890-CH1-DontLinkElementID_27) – oisdk Jun 30 '15 at 22:25
  • Note: this works in Swift 2. For 1.2, use `return paths.filter({$0 != nil}).map({$0 as String!})` – SushiGrass Jacob Jul 01 '15 at 14:10
5

You should filter first, and map next:

return paths.filter { $0 != .None }.map { $0 as! String }

but using flatMap as suggested by @BradLarson is a just better

Antonio
  • 71,651
  • 11
  • 148
  • 165
1

Perhaps what you want to is a filter followed by a map:

func cleanPaths() -> [String] {
    return paths()
            .filter {$0 != nil}
            .map {$0 as String!}
}

let x = cleanPaths()
println(x) // ["test", "two"]
Code Different
  • 90,614
  • 16
  • 144
  • 163
-1
let name = obj.value
name.map { name  in print(name)}
Venu Gopal Tewari
  • 5,672
  • 42
  • 41