按 Swift 中的不同 属性 值对自定义对象进行排序
Sorting a Custom Object by different property values in Swift
我正在尝试按不同的 属性 值轻松地对自定义结构数组进行排序。
struct Customer: Comparable, Equatable {
var name: String
var isActive: Bool
var outstandingAmount: Int
var customerGroup: String
}
var customerlist: [Customer] // This is downloaded from our backend.
我希望能够在用户选择各种图标时按所有字段值对 UI 中的客户列表数组进行排序。
我已经尝试了几种使用 switch 语句对其进行排序的方法 - 但是有人告诉我正确的方法是使用排序描述符(这似乎是基于 Objective-C 的,这意味着我需要将我的数组转换为 NSArray。)当我使用本机 Swift 结构尝试这种方法时,我不断收到错误消息。
允许用户使用 Swift 对上述数组进行排序的最佳方法是什么?
例如:下面看起来很冗长!
func sortCustomers(sortField:ColumnOrder, targetArray:[Customer]) -> [Customer] { //Column Order is the enum where I have specified the different possible sort orders
var result = [Customer]()
switch sortField {
case .name:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.name > cust1.name
})
case .isActive:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.isActive > cust1.isActive
})
case .outstandingAmount:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.outstandingAmount > cust1.outstandingAmount
})
case .customerGroup:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.customerGroup > cust1.customerGroup
})
}
return result
}
我会使用 KeyPaths:
func sortCustomers<T: Comparable>(customers: [Customer], with itemPath: KeyPath<Customer, T>) -> [Customer] {
return customers.sorted() {
[=10=][keyPath: itemPath] < [keyPath: itemPath]
}
}
这种方法完全避免了对枚举的需要,并允许您只做
let testData = [Customer(name: "aaaa", isActive: false, outstandingAmount: 1, customerGroup: "aaa"),
Customer(name: "bbbb", isActive: true, outstandingAmount: 2, customerGroup: "bbb")];
let testResultsWithName = sortCustomers(customers: testData, with: \Customer.name)
let testResultsWithActive = sortCustomers(customers: testData, with: \Customer.isActive)
// etc
请注意,我将 >
切换为 <
。这是默认的期望,将导致 "a" 在 "b" 之前,“1”在“2”之前,等等
此外,您需要为 Bool 添加扩展以进行比较:
extension Bool: Comparable {
public static func <(lhs: Bool, rhs: Bool) -> Bool {
return lhs == rhs || (lhs == false && rhs == true)
}
}
为了完善方法,您还可以传入一个比较函数:
func sortCustomers<T: Comparable>(customers: [Customer], comparing itemPath: KeyPath<Customer, T>, using comparitor: (T, T) -> Bool) -> [Customer] {
return customers.sorted() {
comparitor([=13=][keyPath: itemPath], [keyPath: itemPath])
}
}
let testResults = sortCustomers(customers: testData, comparing: \Customer.name, using: <)
这样您就可以使用普通的比较运算符:(<、<=、>、>=),如果您想要自定义排序,也可以使用闭包。
我重新打包了冗长的解决方案以使其变得更好。我添加了一个 属性 到 ColumnOrder
,returns 一个排序闭包。
struct Customer {
var name: String
var isActive: Bool
var outstandingAmount: Int
var customerGroup: String
}
enum ColumnOrder {
case name
case isActive
case outstandingAmount
case customerGroup
var ordering: (Customer, Customer) -> Bool {
switch self {
case .name: return { [=10=].name > .name }
case .isActive: return { [=10=].isActive && !.isActive }
case .outstandingAmount: return { [=10=].outstandingAmount > .outstandingAmount}
case .customerGroup: return { [=10=].customerGroup > .customerGroup }
}
}
}
使用方法如下:
let sortedCustomers = customers.sorted(by: ColumnOrder.name.ordering)
接下来,我扩展了 Sequence
以便从数组中调用它看起来不错。
extension Sequence where Element == Customer {
func sorted(by columnOrder: ColumnOrder) -> [Element] {
return sorted(by: columnOrder.ordering)
}
}
最终结果:
let sortedCustomers = customers.sorted(by: .name)
我正在尝试按不同的 属性 值轻松地对自定义结构数组进行排序。
struct Customer: Comparable, Equatable {
var name: String
var isActive: Bool
var outstandingAmount: Int
var customerGroup: String
}
var customerlist: [Customer] // This is downloaded from our backend.
我希望能够在用户选择各种图标时按所有字段值对 UI 中的客户列表数组进行排序。
我已经尝试了几种使用 switch 语句对其进行排序的方法 - 但是有人告诉我正确的方法是使用排序描述符(这似乎是基于 Objective-C 的,这意味着我需要将我的数组转换为 NSArray。)当我使用本机 Swift 结构尝试这种方法时,我不断收到错误消息。
允许用户使用 Swift 对上述数组进行排序的最佳方法是什么?
例如:下面看起来很冗长!
func sortCustomers(sortField:ColumnOrder, targetArray:[Customer]) -> [Customer] { //Column Order is the enum where I have specified the different possible sort orders
var result = [Customer]()
switch sortField {
case .name:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.name > cust1.name
})
case .isActive:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.isActive > cust1.isActive
})
case .outstandingAmount:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.outstandingAmount > cust1.outstandingAmount
})
case .customerGroup:
result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in
return cust0.customerGroup > cust1.customerGroup
})
}
return result
}
我会使用 KeyPaths:
func sortCustomers<T: Comparable>(customers: [Customer], with itemPath: KeyPath<Customer, T>) -> [Customer] {
return customers.sorted() {
[=10=][keyPath: itemPath] < [keyPath: itemPath]
}
}
这种方法完全避免了对枚举的需要,并允许您只做
let testData = [Customer(name: "aaaa", isActive: false, outstandingAmount: 1, customerGroup: "aaa"),
Customer(name: "bbbb", isActive: true, outstandingAmount: 2, customerGroup: "bbb")];
let testResultsWithName = sortCustomers(customers: testData, with: \Customer.name)
let testResultsWithActive = sortCustomers(customers: testData, with: \Customer.isActive)
// etc
请注意,我将 >
切换为 <
。这是默认的期望,将导致 "a" 在 "b" 之前,“1”在“2”之前,等等
此外,您需要为 Bool 添加扩展以进行比较:
extension Bool: Comparable {
public static func <(lhs: Bool, rhs: Bool) -> Bool {
return lhs == rhs || (lhs == false && rhs == true)
}
}
为了完善方法,您还可以传入一个比较函数:
func sortCustomers<T: Comparable>(customers: [Customer], comparing itemPath: KeyPath<Customer, T>, using comparitor: (T, T) -> Bool) -> [Customer] {
return customers.sorted() {
comparitor([=13=][keyPath: itemPath], [keyPath: itemPath])
}
}
let testResults = sortCustomers(customers: testData, comparing: \Customer.name, using: <)
这样您就可以使用普通的比较运算符:(<、<=、>、>=),如果您想要自定义排序,也可以使用闭包。
我重新打包了冗长的解决方案以使其变得更好。我添加了一个 属性 到 ColumnOrder
,returns 一个排序闭包。
struct Customer {
var name: String
var isActive: Bool
var outstandingAmount: Int
var customerGroup: String
}
enum ColumnOrder {
case name
case isActive
case outstandingAmount
case customerGroup
var ordering: (Customer, Customer) -> Bool {
switch self {
case .name: return { [=10=].name > .name }
case .isActive: return { [=10=].isActive && !.isActive }
case .outstandingAmount: return { [=10=].outstandingAmount > .outstandingAmount}
case .customerGroup: return { [=10=].customerGroup > .customerGroup }
}
}
}
使用方法如下:
let sortedCustomers = customers.sorted(by: ColumnOrder.name.ordering)
接下来,我扩展了 Sequence
以便从数组中调用它看起来不错。
extension Sequence where Element == Customer {
func sorted(by columnOrder: ColumnOrder) -> [Element] {
return sorted(by: columnOrder.ordering)
}
}
最终结果:
let sortedCustomers = customers.sorted(by: .name)