Proper way to concatenate optional swift strings?
Somewhere, I believe in the swift book, I ran into this pattern, from when before you could have multiple lets in a single if:
class User {
var lastName : String?
var firstName : String?
var fullName : String {
switch (firstName, lastName) {
case (.Some, .Some):
return firstName! + " " + lastName!
case (.None, .Some):
return lastName!
case (.Some, .None):
return firstName!
default:
return ""
}
}
init(lastName:String?, firstName:String?) {
self.lastName = lastName
self.firstName = firstName
}
}
User(lastName: nil, firstName: "first").fullName // -> "first"
User(lastName: "last", firstName: nil).fullName // -> "last"
User(lastName: nil, firstName: nil).fullName // -> ""
User(lastName: "last", firstName: "first").fullName // -> "first last"
An even briefer solution, given swift 3.0:
var fullName : String {
return [ firstName, lastName ].flatMap({$0}).joined(separator:" ")
}
Here is an alternative method:
let name =
(person.first != nil && person.last != nil) ?
person.first! + " " + person.last! :
person.first ?? person.last!
Sometimes simple is best:
let first = p.first ?? ""
let last = p.last ?? ""
let both = !first.isEmpty && !last.isEmpty
let full = first + (both ? " " : "") + last
This works if there is no first
or last
, if there is a first
but no last
, if there is a last
but no first
, and if there are both a first
and a last
. I can't think of any other cases.
Here's an idiomatic incorporation of that idea into a calculated variable; as an extra benefit, I've allowed full
to be nil
just in case both the other names are nil
:
struct Person {
var first : String?
var last : String?
var full : String? {
if first == nil && last == nil { return nil }
let fi = p.first ?? ""
let la = p.last ?? ""
let both = !fi.isEmpty && !la.isEmpty
return fi + (both ? " " : "") + la
}
}
compactMap
would work well here, combined with .joined(separator:)
:
let f: String? = "jo"
let l: String? = "smith"
[f,l] // "jo smith"
.compactMap { $0 }
.joined(separator: " ")
It doesn't put the space between if one is nil
:
let n: String? = nil
[f,n] // "jo"
.compactMap { $0 }
.joined(separator: " ")