如何简化此Swift排序代码?
我正在用自己的数据处理一个问题。我已经到了编写排序函数的地步,这就是我想到的:如何简化此Swift排序代码?,swift,sorting,Swift,Sorting,我正在用自己的数据处理一个问题。我已经到了编写排序函数的地步,这就是我想到的: var payment_list: [Payment]! func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) { guard let sortDescriptor = tableView.sortDescriptors.first else {
var payment_list: [Payment]!
func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
guard let sortDescriptor = tableView.sortDescriptors.first else {
return
}
let key = sortDescriptor.key!
if sortDescriptor.ascending == true {
if key == "id" {
payment_list.sort { $0.id < $1.id }
} else if key == "msatoshi" {
payment_list.sort { $0.msatoshi < $1.msatoshi }
} else if key == "created_at" {
payment_list.sort { $0.created_at < $1.created_at }
} else if key == "status" {
payment_list.sort { $0.status < $1.status }
}
} else {
if key == "id" {
payment_list.sort(by: { $0.id > $1.id })
} else if key == "msatoshi" {
payment_list.sort { $0.msatoshi > $1.msatoshi }
} else if key == "created_at" {
payment_list.sort { $0.created_at > $1.created_at }
} else if key == "status" {
payment_list.sort { $0.status > $1.status }
}
}
tableView.reloadData()
}
我得到的印象是,在Swift开发中,有很多巨大的嵌套if…else if和/或switch…case块。这是准确的评估吗
更新:
这是我的付款定义:
struct Payment: Codable, PaymentFactory {
let id: Int
let payment_hash: String
let destination: String
let msatoshi: Int
let timestamp: Int
let created_at: Int
let status: String
enum PaymentKeys: String, CodingKey {
case payments
}
static func fake() -> Payment {
// snipped for brevity
}
}
添加一个枚举来处理各种排序描述符键怎么样?然后,您可以向Payment类添加一个函数,该函数根据传入的枚举值返回正确的属性,这使得实际的排序函数非常简洁
例如,如果所有属性都是int,则可以执行以下操作:
enum Key: String {
case id = "id", amount = "amount", createdAt = "createdAt", status = "status"
}
class Payment {
let id: Int
let amount: Int
let createdAt: Int
let status: Int
func attribute(forKey key: Key) -> Int {
switch key {
case .id: return self.id
case .amount: return self.amount
case .createdAt: return self.createdAt
case .status: return self.status
}
}
}
enum Key: String {
case id = "id", amount = "amount", createdAt = "createdAt", status = "status"
}
class Payment {
let id: Int
let amount: Int
let createdAt: Int
let status: String
func compare(toOther other: Payment, byKey key: Key, ascending: Bool) -> Bool {
switch key {
case .id:
return ascending ? self.id < other.id : self.id > other.id
case .amount:
return ascending ? self.amount < other.amount : self.amount > other.amount
case .createdAt:
return ascending ? self.createdAt < other.createdAt : self.createdAt > other.createdAt
case .status:
return ascending ? self.status < other.status : self.status > other.status
}
}
}
let sortDescriptor = NSSortDescriptor(key: "amount", ascending: true)
let key = Key(rawValue: sortDescriptor.key!)!
paymentList.sort(by: { $0.compare(toOther: $1, byKey: key, ascending: sortDescriptor.ascending) })
当需要排序时,您可以这样做:
let key = Key(rawValue: sortDescriptor.key!)!
if sortDescriptor.ascending {
paymentList.sort(by: { $0.attribute(forKey: key) < $1.attribute(forKey: key) })
} else {
paymentList.sort(by: { $0.attribute(forKey: key) > $1.attribute(forKey: key) })
}
这将使您的排序如下所示:
enum Key: String {
case id = "id", amount = "amount", createdAt = "createdAt", status = "status"
}
class Payment {
let id: Int
let amount: Int
let createdAt: Int
let status: Int
func attribute(forKey key: Key) -> Int {
switch key {
case .id: return self.id
case .amount: return self.amount
case .createdAt: return self.createdAt
case .status: return self.status
}
}
}
enum Key: String {
case id = "id", amount = "amount", createdAt = "createdAt", status = "status"
}
class Payment {
let id: Int
let amount: Int
let createdAt: Int
let status: String
func compare(toOther other: Payment, byKey key: Key, ascending: Bool) -> Bool {
switch key {
case .id:
return ascending ? self.id < other.id : self.id > other.id
case .amount:
return ascending ? self.amount < other.amount : self.amount > other.amount
case .createdAt:
return ascending ? self.createdAt < other.createdAt : self.createdAt > other.createdAt
case .status:
return ascending ? self.status < other.status : self.status > other.status
}
}
}
let sortDescriptor = NSSortDescriptor(key: "amount", ascending: true)
let key = Key(rawValue: sortDescriptor.key!)!
paymentList.sort(by: { $0.compare(toOther: $1, byKey: key, ascending: sortDescriptor.ascending) })
如果您的付款类型是NSObject,则可以使用@objc标记数据字段,并使用NSSortDescriptor的内置比较功能。它甚至可以自动处理升序/降序
工作区代码段:
import Foundation
class Payment: NSObject {
@objc var id: String
@objc var amount: Double
@objc var created_at: Date
@objc var status: String
init(id: String, amount: Double, created_at: Date, status: String) {
self.id = id
self.amount = amount
self.created_at = created_at
self.status = status
super.init()
}
}
let arr: [Payment] = [
Payment(id: "1", amount: 123, created_at: Date(), status: "abc"),
Payment(id: "5", amount: 123, created_at: Date(), status: "abc"),
Payment(id: "4", amount: 123, created_at: Date(), status: "abc"),
Payment(id: "2", amount: 123, created_at: Date(), status: "abc")
]
let sd = NSSortDescriptor(key: "id", ascending: true)
let sorted = arr.sorted { sd.compare($0, to: $1) == .orderedAscending }
dump(sorted)
确切地说,为什么不使用switch构造呢?switch与if…else的首选项不会改变代码的总体详细程度。它实际上会使用标准格式添加八行代码。您的支付类是什么样子的?你所有的属性都是什么类型的?你检查key的值,它可以有一个不同的值。我认为控制语句是你使用Swift 4的唯一方法?这与我要寻找的非常接近,但我的对象中也有字符串。我已经更新了问题。@BenHarold查看我的编辑。我并没有为我的示例添加所有关键点,但这很有效。