Extending Array to check if it is sorted in Swift?

前端 未结 11 2402
清歌不尽
清歌不尽 2020-12-13 14:23

I want to extend Array class so that it can know whether it is sorted (ascending) or not. I want to add a computed property called isSorted. How can I state the

相关标签:
11条回答
  • 2020-12-13 14:47

    The generic function, zip(), can provide a shortcut for implementation.

    extension Collection where Element: Comparable {
        var isSorted: Bool {
            guard count > 1 else {
                return true 
            }
    
            let pairs = zip(prefix(count - 1), suffix(count - 1))
    
            return !pairs.contains { previous, next in
                previous > next
            }
        }
    }
    
    [0, 1, 1, 2].isSorted  // true
    [0, 2, 2, 1].isSorted  // false
    
    0 讨论(0)
  • 2020-12-13 14:47

    @kAzec's answer seems to not working when elements are equal. This is because areInIncreasingOrder(a, a) must be false according to the documentation.

    The following should work fine.

    extension Sequence {
        func isSorted(by areInIncreasingOrder: (Element, Element) throws -> Bool)
            rethrows -> Bool {
            var it = makeIterator()
            guard var previous = it.next() else { return true }
            
            while let current = it.next() {
                if try !areInIncreasingOrder(previous, current) &&
                    areInIncreasingOrder(current, previous) {
                    return false
                }
                previous = current
            }
            return true
        }
    }
    
    extension Sequence where Element: Comparable {
        func isSorted() -> Bool {
            return isSorted(by: <)
        }
    }
    
    0 讨论(0)
  • 2020-12-13 14:51

    The alternative solution to a free function is to do what Swift's built-in Array.sort and Array.sorted methods do, and require that you pass a suitable comparator to the method:

    extension Array {
        func isSorted(isOrderedBefore: (T, T) -> Bool) -> Bool {
            for i in 1..<self.count {
                if !isOrderedBefore(self[i-1], self[i]) {
                    return false
                }
            }
            return true
        }
    }
    
    [1, 5, 3].isSorted(<) // false
    [1, 5, 10].isSorted(<) // true
    [3.5, 2.1, -5.4].isSorted(>) // true
    
    0 讨论(0)
  • 2020-12-13 14:51

    If you want simple function without arguments, like sort() or sorted() in Swift:

    extension Array where Element : Comparable {
        func isSorted() -> Bool {
            guard self.count > 1 else {
                return true
            }
    
            for i in 1..<self.count {
                if self[i-1] > self[i] {
                    return false
                }
            }
            return true
        }
    }
    
    0 讨论(0)
  • 2020-12-13 14:55

    In Swift 4.2 and later you can cobble together allSatisfy and zip with some sequence slicing:

    extension Array where Element: Comparable {
        func isAscending() -> Bool {
            return zip(self, self.dropFirst()).allSatisfy(<=)
        }
    
        func isDescending() -> Bool {
            return zip(self, self.dropFirst()).allSatisfy(>=)
        }
    }
    
    0 讨论(0)
  • 2020-12-13 14:57

    Actually, you can extend the Sequence protocol for a more generic solution:

    extension Sequence {
        func isSorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Bool {
            var iterator = makeIterator()
    
            guard var previous = iterator.next() else {
                // Sequence is empty
                return true
            }
    
            while let current = iterator.next() {
                guard try areInIncreasingOrder(previous, current) else {
                    return false
                }
    
                previous = current
            }
    
            return true
        }
    }
    
    extension Sequence where Element : Comparable {
        func isSorted() -> Bool {
            return isSorted(by: <)
        }
    }
    
    0 讨论(0)
提交回复
热议问题