gpt4 book ai didi

swift - 如何有条件地在协议(protocol)扩展方法实现之间切换?

转载 作者:行者123 更新时间:2023-11-28 08:01:07 25 4
gpt4 key购买 nike

深入研究函数式编程和快速整体,我对多种做事方式感到不知所措。在这种情况下,我希望 struct 采用 Comparable 但可以有条件地切换重载运算符中正在使用的属性。

假设我有以下内容,一个快速排序(来自 Niv Yahel 的 Wenderlich FP 教程),扩展了任何可比较的数组,这将很容易地容纳我的 CollectionStudent

struct Student {
let name: String
let age: Int
let grades: Double
}

extension Student: Comparable {
static func <(lhs: Student, rhs: Student) -> Bool {
return lhs.grades < rhs.grades
}
static func ==(lhs: Student, rhs: Student) -> Bool {
return lhs.grades == rhs.grades
}
}

extension Array where Element: Comparable {
func quickSorted() -> [Element] {
if self.count > 1 {
let (pivot, remaining) = (self[0], dropFirst())
let lhs = remaining.filter{ $0 <= pivot }
let rhs = remaining.filter{ $0 > pivot }
return lhs.quickSorted() as [Element] + pivot + rhs.quickSorted()
}
return self
}
}
}

//Omitted, create a bunch of Students
//let bingoLittle = Student(name: "BingoLittle", age: 23, grades: 93.4)
let myStudentDirectory = [bingoLittle, studentB, ... StudentN]
let sortedStudentDirectory = myStudentDirectory.quickSorted()

但是,下一步我想要的是即时决定结构将按哪个 property 排序,无论是姓名、成绩还是年龄,最好不必触及这个 nice快速排序功能。

  1. 是否应该将快速排序变成通用函数?
  2. 我应该考虑类型约束吗?
  3. 我是否应该在 Student 中有一个属性,它是应该根据哪个属性排序的枚举?看起来很丑。
  4. 我应该有一个类似于 quickSorted(by: .name) 的快速排序吗?它似乎不再适用于数组扩展。

最佳答案

有几种方法可以解决这个问题:

1) 使用 native 排序函数,它允许您为比较指定一个闭包,从而提供更多的灵 active ,并且不需要您的结构是可比较的:

let sortedStudentDirectory = myStudentDirectory.sorted{ $0.grade < $1.grade }

//
// This would be my recommendation given that it is standard and
// it is unlikely that the quicksorted() method would outperform it.
//

2) 修改 quicksorted() 函数以让它与闭包一起工作:

extension Array 
{
func quickSorted<T:Comparable>(_ property:@escaping (Element)->T) -> [Element]
{
guard self.count > 1 else { return self }
let (pivot, remaining) = (property(self[0]), dropFirst())
let lhs = remaining.filter{ property($0) <= pivot }
let rhs = remaining.filter{ property($0) > pivot }
return lhs.quickSorted(property) as [Element] + self[0] + rhs.quickSorted(property)
}
}

let sortedStudentDirectory = myStudentDirectory.quickSorted{$0.grades}

// this one also avoids making the struct Comparable.
// you could implement it like the standard sort with a comparison
// closure instead of merely a property accessor so that descending
// sort order and multi-field sorting can be supported.

.

3) 向您的 Student 结构添加一个静态变量,以告诉您的比较运算符要使用哪个字段,并在使用 quicksorted() 函数之前设置该静态变量

struct Student
{
enum SortOrder { case name, age, grades }
static var sortOrder = .grades
let name: String
let age: Int
let grades: Double
}

extension Student: Comparable
{
static func <(lhs: Student, rhs: Student) -> Bool
{
switch Student.sortOrder
{
case .grades : return lhs.grades < rhs.grades
case .age : return lhs.age < rhs.age
default : return lhs.name < rhs.name
}
}

static func ==(lhs: Student, rhs: Student) -> Bool
{
switch Student.sortOrder
{
case .grades : return lhs.grades == rhs.grades
case .age : return lhs.age == rhs.age
default : return lhs.name == rhs.name
}
}
}

Student.sortOrder = .grades
let sortedStudentDirectory = myStudentDirectory.quickSorted()

最后一个非常糟糕且容易出错,因为它会影响可能不打算对其进行排序的结构上的其他比较操作(特别是对于 == 运算符)。它也不是线程安全的。

关于swift - 如何有条件地在协议(protocol)扩展方法实现之间切换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46676332/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com