Swift 2 - Правильный способ конкатенации необязательных строк?
Предположим, что у меня есть экземпляр класса Person
с именем Person
с именами first
и last
, которые являются необязательными строками.
Теперь я хочу построить строку fullName
, содержащую либо только их первое или последнее имя (если это все, что доступно), либо если у нас есть оба их имени и фамилии с пространством посередине.
var fullName : String?
if let first = person.first {
name = first
}
if let last = person.last {
if name == nil {
name = last
} else {
name! += " " + last
}
}
или
var name = ""
if let first = person.first {
name = first
}
if let last = person.last {
name = name.characters.count > 0 ? name + " " + last : last
}
Я понимаю варианты, но я не могу полностью обернуть голову вокруг "быстрого" способа мышления о них и безопасного развертывания. Мы просто должны вложить if let
? Есть ли более чистый, более "быстрый" способ сделать это? Нил coalescing кажется подходящим, но я не могу придумать, как применить его в этом сценарии. Я не могу не чувствовать, что я делаю необязательную конкатенацию строк чрезмерно сложным способом.
Ответы
Ответ 1
flatMap
будет работать хорошо, с joinWithSeparator
:
let f: String? = "jo"
let l: String? = "smith"
[f,l] // "jo smith"
.flatMap{$0}
.joinWithSeparator(" ")
Он не помещает пробел между ними, если один nil
:
let n: String? = nil
[f,n] // "jo"
.flatMap{$0}
.joinWithSeparator(" ")
Ответ 2
Иногда простое:
let first = p.first ?? ""
let last = p.last ?? ""
let both = !first.isEmpty && !last.isEmpty
let full = first + (both ? " " : "") + last
Это работает, если нет first
или last
, если есть first
, но no last
, если есть last
, но не first
, и если есть и first
и a last
. Я не могу думать о других случаях.
Здесь идиоматическое включение этой идеи в вычисленную переменную; в качестве дополнительного преимущества я разрешил full
быть nil
на всякий случай, если остальные имена 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
}
}
Ответ 3
Где-то, я верю в быструю книгу, я столкнулся с этим шаблоном, начиная с того момента, когда до вас можно было бы иметь несколько разрешений в одном, если:
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"
Равномерное решение, учитывая скорость 3,0:
var fullName : String {
return [ firstName, lastName ].flatMap({$0}).joined(separator:" ")
}
Ответ 4
Вот альтернативный метод:
let name =
(person.first != nil && person.last != nil) ?
person.first! + " " + person.last! :
person.first ?? person.last!
Ответ 5
Мне нравится oisdk подход, но мне не понравилась пустая строка, если оба были nil
. Я предпочел бы nil
.
func add(a a: String?, b: String?, separator: String = " ") -> String? {
let results = [a, b].flatMap {$0}
guard results.count > 0 else { return nil }
return results.joinWithSeparator(separator)
}
Ответ 6
Какой oisdk ответил, было здорово, но мне нужно было что-то очень специфическое в соответствии с исходным вопросом OP.
Написание для Swift 3.0, я создал это расширение, которое хорошо работает при заполнении других строк, таких как текстовые метки.
extension String {
func combine(firstName: String?, lastName: String?) -> String {
return [firstName, lastName].flatMap{$0}.joined(separator: " ")
}
}
Пример этого заполнения текстовой метки:
textLabel.text? = String().combine(firstName: "First", lastName: "Last")
Невзирая на мои потребности, вы также можете изменить его, чтобы вместо этого принять массив строк, чтобы вы могли объединить больше элементов.
Ответ 7
добавьте это расширение:
extension String { var stringValue:String {
return "\(self)"
}
}
Затем объединить
let f: String? = "jo"
let l: String? = "smith"
print("\(f.stringValue)\(l.stringValue)")
// "jo smith"