我试图通过不同的属性值对自定义结构进行分类。
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对上述数组进行排序的最佳方法是什么?
eg:下面似乎很详细!
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
}
我要使用的是键盘:
func sortCustomers<T: Comparable>(customers: [Customer], with itemPath: KeyPath<Customer, T>) -> [Customer] {
return customers.sorted() {
$0[keyPath: itemPath] < $1[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
请注意,我将>
切换到<
。那是默认期望,将在" b"之前导致" A"," 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($0[keyPath: itemPath], $1[keyPath: itemPath])
}
}
let testResults = sortCustomers(customers: testData, comparing: Customer.name, using: <)
这样,您可以使用普通比较操作员:(&lt;,&lt; =,>,> =)以及如果要自定义排序。
我重新包装了冗长的解决方案,以使某些东西变得更好。我向ColumnOrder
添加了一个属性,该属性返回订购关闭。
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 { $0.name > $1.name }
case .isActive: return { $0.isActive && !$1.isActive }
case .outstandingAmount: return { $0.outstandingAmount > $1.outstandingAmount}
case .customerGroup: return { $0.customerGroup > $1.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)