我一直在使用sort()函数,但它混合了相对顺序。
这是我的代码的样子。
recipes.sort { $0.skill.value <= $1.skill.value }
排序算法不稳定。不稳定的排序可能会改变 比较相等的元素的相对顺序。
如何更改此设置以使相对顺序与以前保持一致?
答案 0 :(得分:16)
下面的实现就像标准库中的sorted
方法一样,没有额外的限制。
extension RandomAccessCollection {
/// return a sorted collection
/// this use a stable sort algorithm
///
/// - Parameter areInIncreasingOrder: return nil when two element are equal
/// - Returns: the sorted collection
public func stableSorted(by areInIncreasingOrder: (Iterator.Element, Iterator.Element) -> Bool?) -> [Iterator.Element] {
let sorted = self.enumerated().sorted { (one, another) -> Bool in
if let result = areInIncreasingOrder(one.element, another.element) {
return result
} else {
return one.offset < another.offset
}
}
return sorted.map{ $0.element }
}
}
稳定排序需要保留原始订单。所以我们给每个元素一个权重除了它的值,索引,然后原始的排序方法将起作用,因为永远不会有2个相等的元素。
答案 1 :(得分:8)
我很欣赏leavez's answer的优雅。我将其改编为与Sequence.sorted(by:)
具有相同的签名:
extension Sequence {
func stableSorted(
by areInIncreasingOrder: (Element, Element) throws -> Bool)
rethrows -> [Element]
{
return try enumerated()
.sorted { a, b -> Bool in
try areInIncreasingOrder(a.element, b.element) ||
(a.offset < b.offset && !areInIncreasingOrder(b.element, a.element))
}
.map { $0.element }
}
}
答案 2 :(得分:7)
let sortedArray = (recipes as NSArray).sortedArray(options: .stable, usingComparator: { (lhs, rhs) -> ComparisonResult in
let lhs = (lhs as! Recipe)
let rhs = (rhs as! Recipe)
if lhs.skill.value == rhs.skill.value {
return ComparisonResult.orderedSame
} else if lhs.skill.value < rhs.skill.value {
return ComparisonResult.orderedAscending
} else {
return ComparisonResult.orderedDescending
}
})
从这里开始:https://medium.com/@cocotutch/a-swift-sorting-problem-e0ebfc4e46d4
答案 3 :(得分:0)
我使用这个包装器
extension Array where Element: Comparable, Element: AnyObject {
public func stableSorted() -> [Element] {
let array = self as NSArray
let result = array.sortedArray(options: .stable) { (left, right) -> ComparisonResult in
let left = left as! Element
let right = right as! Element
if left < right {
return ComparisonResult.orderedAscending
}
if left > right {
return ComparisonResult.orderedDescending
}
return ComparisonResult.orderedSame
}
return result as! [Element]
}
public func stableReversed() -> [Element] {
let array = self as NSArray
let result = array.sortedArray(options: .stable) { (left, right) -> ComparisonResult in
let left = left as! Element
let right = right as! Element
if left > right {
return ComparisonResult.orderedAscending
}
if left < right {
return ComparisonResult.orderedDescending
}
return ComparisonResult.orderedSame
}
return result as! [Element]
}
}
答案 4 :(得分:0)
在Swift 5 sort()
中使用稳定的实现方式,不久后它将正式保证稳定。
来自Swift forums:
...
另一方面,实际的实现调用/// Sorts the elements of this buffer according to `areInIncreasingOrder`, /// using a stable, adaptive merge sort. /// /// The adaptive algorithm used is Timsort, modified to perform a straight /// merge of the elements using a temporary buffer. @inlinable public mutating func _stableSortImpl( by areInIncreasingOrder: (Element, Element) throws -> Bool ) rethrows { ... }
和
如果我记得,sort()目前是稳定的,但尚不能保证 保持稳定(意思是,它目前处于稳定状态 实施细节,而Swift的未来版本可能会发布 而是使用不稳定算法。