是否有任何方法来排序的姓和名只使用Swift 5+?



我一直在绞尽脑汁想找出一种按姓氏和名字排序字符串的方法。我有这个正常的排序实现(见下文),但想扩展一下。

排序功能:

@objc func handleSortByName() {
let sortedList: [List] = self.viewModel.names.sorted() { $0.fullName < $1.fullName }
replaceNewList(newList: sortedList)
}

我正在考虑遍历字符串并检查空格后的字符是否低于下一个字符串在空格后的字符,但我根本无法理解。

遍历字符串中的字符是可行的,但考虑到名称由两部分组成,需要分别进行比较,并且每个名称的长度可能不同,因此要正确处理和维护将是棘手的。

一种更简单的方法是将名字拆分为分别包含名字和姓氏的部分,并使用它来进行比较。

为了给出一个代码示例,我需要一些明确的格式,所以让我们假设你的名字看起来都像"Bobby Landry", "Sarah McMillan"等等…基本上,第一个非空白子字符串是名字,后跟一个空格,然后是更多的非空白组成的姓氏,没有更多的空格。如果您的实际格式不同,则需要适当地修改FirstLast.init

我还假设主排序应该是姓氏,次排序应该是名字。您可以修改func <实现来做您实际需要的事情。

@objc func handleSortByName() 
{
struct FirstLast: Comparable
{
let first: Substring
let last : Substring
init(_ name: String)
{
guard let spaceIndex = name.firstIndex(of: " ") else {
fatalError("Missing space - do something more appropriate here")
}
guard let lastNameStartIndex = name.index(after: spaceIndex) else {
fatalError("No last name - do something more appropriate here")
}
self.first = name[..<spaceIndex]
self.last  = name[lastNameStartIndex...]
}
// Primary sort by last name, secondary sort on first
static func < (left: Self, right: Self) -> Bool
{
return left.last == right.last
? left.first < right.first
: left.last < right.last
}
}
let sortedList: [List] = self.viewModel.names.sorted() {
FirstLast($0.fullName) < FirstLast($1.fullName)
}
replaceNewList(newList: sortedList)
}

我选择使FirstLast为本地类型,只是因为我假设没有其他需要它。您可以将它移到handleSortByName之外,如果您认为它对其他代码有用的话。

如果没有太多的名字,应该可以正常工作;但是,它将为每个比较构造一对FirstLast,因为它们只存在于比较闭包中,并且每个比较都涉及搜索第一个空间以分割名称。

对于大量的名称,在整个排序中只构造一次FirstLast实例更有意义,这样它们就可以在所有比较中重用。一种方法是将[List]映射到[FirstLast],然后对[FirstLast]数组的索引进行排序,然后使用它来创建排序的[List]:

@objc func handleSortByName() 
{
struct FirstLast: Comparable
{
// Same implementation as above
...
}
let firstLastNames = self.viewModel.names.map { FirstLast($0.fullName) }
var firstLastIndices = [Int](firstLastNames.indices)
firstLastIndices.sort { firstLastNames[$0] < firstLastNames[$1] }
let sortedList: [List] = firstLastIndices.map { self.viewModel.names[$0] }
replaceNewList(newList: sortedList)
}

最新更新