我正在尝试找到获取字符串数组中最长字符串的最有效方法。例如:
let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]
结果将是 -
"Game Of Thrones is just good"
我尝试过使用
maxElement
函数,但它给出了字母顺序中的最大字符串(maxElement()
)。
有什么建议吗?谢谢!
不要使用 O(n log(n)) 进行良好排序,而是使用
max(by:)
(数组上的 O(n))为其提供一个闭包来比较字符串长度:
斯威夫特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: {$1.count > $0.count}) {
print(max)
}
斯威夫特3:
在
.characters.count
上使用 String
来获取字符串长度:
let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]
if let max = array.max(by: {$1.characters.count > $0.characters.count}) {
print(max)
}
斯威夫特2:
在数组上使用
maxElement
为其提供一个闭包来比较字符串长度:
let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]
if let max = array.maxElement({$1.characters.count > $0.characters.count}) {
print(max)
}
注:
maxElement
为 O(n)。好的排序是 O(n log(n)),因此对于大型数组,这将比排序快得多。
您可以使用
reduce
来执行此操作。它将迭代您的数组,跟踪当前最长的字符串,然后在完成后返回它。
例如:
let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]
if let longestString = array.reduce(Optional<String>.None, combine:{$0?.characters.count > $1.characters.count ? $0:$1}) {
print(longestString) // "Game Of Thrones is just good"
}
(请注意,
Optional.None
现在在 Swift 3 中是 Optional.none
)
这使用
nil
起始值来解释数组可能为空的事实,正如 @JHZ 所指出的(在这种情况下它将返回 nil
)。如果您知道数组至少有一个元素,则可以将其简化为:
let longestString = array.reduce("") {$0.characters.count > $1.characters.count ? $0:$1}
因为它只迭代每个元素一次,所以它比使用
sort()
更快。我做了一个快速基准测试,sort()
看起来慢了大约 20 倍(尽管过早优化没有意义,但我觉得值得一提)。
编辑:我建议您使用@vacawama的解决方案,因为它比
reduce
更干净!
给你:
let array = ["I'm Roi","I'm asking here","Game Of Thrones is just good"]
var sortedArr = array.sort() { $0.characters.count > $1.characters.count }
let longestEelement = sortedArr[0]
@vacawama 是一个很好的选择,但需要考虑的一件事是您可能有多个相同长度的元素。所以:“获取字符串数组中最长的字符串”的结果可能是多个长度相同的String。如果是这样的话,这可能会起作用:
if let max = array.max(by: {$1.count > $0.count}) {
let largeStrings = array.filter{$0.count == max.count}
print(largeStrings)
}
您还可以通过创建此函数来练习使用泛型:
func longestString<T:Sequence>(from stringsArray: T) -> String where T.Iterator.Element == String{
return (stringsArray.max {$0.count < $1.count}) ?? ""
}
说明:创建一个名为longestString的函数。声明有一个实现 Sequence 协议的泛型类型 T(Sequence 在这里定义:https://developer.apple.com/documentation/swift/sequence)。 该函数将返回单个字符串(当然是最长的)。 where 子句解释了泛型类型 T 应该限制为具有 String 类型的元素。
在函数内部,通过比较内部元素的最长字符串来调用stringsArray的max函数。 将返回的是最长的字符串(可选,因为如果数组为空,它可以为 nil)。如果最长字符串为零,则(使用 ??)返回一个空字符串作为最长字符串。
现在称呼它:
let longestA = longestString(from:["Shekinah", "Chesedh", "Agape Sophia"])
如果您掌握了使用泛型的窍门,即使字符串隐藏在对象内部,您也可以利用上面的编码模式。您可以将元素更改为同一类的对象(例如 Person)。
因此:
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 {$0.name.count < $1.name.count})?.name ?? ""
}
然后像这样调用函数:
let longestB = longestName(from:[Person(name: "Shekinah"), Person(name: "Chesedh"), Person(name: "Agape Sophia")])
您还可以根据其用途的适当性来重命名您的函数。您可以调整模式以返回其他内容,例如对象本身或字符串的长度(计数)。最后,熟悉泛型可能会提高您的编码能力。
现在,再次稍作调整,您可以进一步扩展,以便可以比较许多不同类型拥有的字符串,只要它们实现通用协议即可。
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 {$0.name.count < $1.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: { $0.count < $1.count }) ?? ""
}
}
或协议类型:
extension Sequence where Iterator.Element == Nameable {
func theLongestName() -> Nameable? {
self.max(by: { $0.name.count < $1.name.count })
}
}