Подтвердить что ты не робот

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 кажется подходящим, но я не могу придумать, как применить его в этом сценарии. Я не могу не чувствовать, что я делаю необязательную конкатенацию строк чрезмерно сложным способом.

4b9b3361

Ответ 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"