Swift - 在 [String] 数组中查找最长字符串的最佳实践

Swift - best practice to find the longest string at [String] array

我正在寻找获取字符串数组中最长字符串的最有效方法。例如:

let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]

结果将是 - "Game Of Thrones is just good"

我试过使用 maxElement 函数,它给出了字母顺序中的最大字符串 (maxElement())。

有什么建议吗?谢谢!

您可以使用 reduce 来做到这一点。它将遍历您的数组,跟踪当前最长的字符串,然后在完成后 return 它。

例如:

let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]

if let longestString = array.reduce(Optional<String>.None, combine:{[=10=]?.characters.count > .characters.count ? [=10=]:}) {
    print(longestString) // "Game Of Thrones is just good"
}

(注意 Optional.None 现在是 Swift 3 中的 Optional.none

这使用 nil 起始值来说明数组可能为空的事实,正如@JHZ 所指出的(在这种情况下它将 return nil) .如果你知道你的数组至少有一个元素,你可以将它简化为:

let longestString = array.reduce("") {[=11=].characters.count > .characters.count ? [=11=]:}

因为它只遍历每个元素一次,所以比使用 sort() 更快。我做了一个快速基准测试,sort() 看起来慢了大约 20 倍(虽然过早优化没有意义,但我觉得值得一提)。


编辑: 我建议您使用@vacawama 的解决方案,因为它比 reduce!

更干净

给你:

let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]

var sortedArr = array.sort() { [=10=].characters.count > .characters.count }

let longestEelement = sortedArr[0]

不要使用 O(n log(n)) 的排序,而是使用 max(by:),即 O(n) 在 Array 上提供闭包来比较字符串长度:

Swift 4:

对于 Swift 4 你可以用 count 属性 在 String:

上得到字符串长度
let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]

if let max = array.max(by: {.count > [=10=].count}) {
    print(max)
}

Swift 3:

String 上使用 .characters.count 获取字符串长度:

let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]

if let max = array.max(by: {.characters.count > [=11=].characters.count}) {
    print(max)
}

Swift 2:

在 Array 上使用 maxElement,为其提供一个闭包来比较字符串长度:

let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]

if let max = array.maxElement({.characters.count > [=12=].characters.count}) {
    print(max)
}

注:maxElementO(n)。一个好的排序是 O(n log(n)),所以对于大型数组,这将比排序快得多。

您还可以通过创建此函数来练习泛型的使用:

func longestString<T:Sequence>(from stringsArray: T) -> String where T.Iterator.Element == String{
    return (stringsArray.max {[=10=].count < .count}) ?? ""
}

解释:创建一个名为 longestString 的函数。声明有一个泛型类型 T 实现了 Sequence 协议(这里定义了 Sequence:https://developer.apple.com/documentation/swift/sequence)。该函数将 return 单个字符串(当然是最长的)。 where 子句说明泛型类型 T 应限于具有 String 类型的元素。

函数内部,通过比较里面元素的最长字符串,调用stringsArray的max函数。 returned 是最长的字符串(一个可选的,因为如果数组为空,它可以是 nil)。如果最长的字符串为 nil,则(使用 ??)returns 一个空字符串作为最长的字符串。

现在称呼它:

let longestA = longestString(from:["Shekinah", "Chesedh", "Agape Sophia"])

如果您掌握了使用泛型的诀窍,即使字符串隐藏在对象中,您也可以使用上面的编码模式。您可以将元素更改为相同 class(例如人)的对象。

因此:

class Person {
    let name: String
    init(name: String){
        self.name = name
    }
}

func longestName<T:Sequence>(from stringsArray: T) -> String where T.Iterator.Element == Person{
    return (stringsArray.max {[=12=].name.count < .name.count})?.name ?? ""
}

然后像这样调用函数:

let longestB = longestName(from:[Person(name: "Shekinah"), Person(name: "Chesedh"), Person(name: "Agape Sophia")])

您还可以根据功能的适用性重命名您的功能。您可以将模式调整为 return 其他内容,例如对象本身或字符串的长度(计数)。最后,熟悉泛型可能会提高您的编码能力。

现在,再次稍作调整,您可以进一步扩展,以便您可以比较许多不同类型拥有的字符串,只要它们实现了通用协议即可。

protocol Nameable {
    var name: String {get}
}

这定义了一个名为 Nameable 的协议,它要求实施者拥有一个 String 类型的名称变量。接下来,我们定义两个不同的东西来实现协议。

class Person: Nameable {
    let name: String
    init(name: String){
        self.name = name
    }
}

struct Pet: Nameable {
    let name: String
}

然后我们调整我们的通用函数,使其要求元素必须符合 Nameable,尽管它们有很大的不同。

func longestName<T:Sequence>(from stringsArray: T) -> String where T.Iterator.Element == Nameable{
return (stringsArray.max {[=16=].name.count < .name.count})?.name ?? ""
}

让我们将不同的对象收集到一个数组中。然后调用我们的函数。

let myFriends: [Nameable] = [Pet(name: "Bailey"), Person(name: "Agape Sophia")]

let longestC = longestName(from: myFriends)

最后,在了解上面的“where”和上面的“Sequence”之后,您可以简单地扩展 Sequence:

extension Sequence where Iterator.Element == String {

    func topString() -> String {
        self.max(by: { [=18=].count < .count }) ?? ""
    }
}

或协议类型:

extension Sequence where Iterator.Element == Nameable {
    func theLongestName() -> Nameable? {
        self.max(by: { [=19=].name.count < .name.count })
    }
}