Search code examples
arraysswiftcomparable

Swift 5, Array of custom object, lowest value. Not equal to other values in same array


How do you determine if this array has only a single lowest value?

let scoresExampleOne = [2, 2, 3, 4] // return false

let scoresExampleTwo = [2, 3, 3, 5] // return true 

"scoreValues" are embedded in a custom "Player" object.

I just tried to simplify it for the sake of this question.


Solution

  • All you need is to iterate your collection and keep track of the minimum value and if it repeats or not:

    extension Collection {
        func minElement<T: Comparable>(_ predicate: (Element) -> T) -> (element: Element, single: Bool)? {
            guard var minElement = first else { return nil }
            var min = predicate(minElement)
            var single = true
            for element in dropFirst() {
                let value = predicate(element)
                if value > min { continue }
                if value < min {
                    minElement = element
                    min = value
                    single = true
                } else {
                    single = false
                }
            }
            return (minElement, single)
        }
        func min<T: Comparable>(_ predicate: (Element) -> T) -> (min: T, single: Bool)? {
            guard let (element, single) = minElement(predicate) else { return nil }
            return (predicate(element), single)
        }
    }
    

    Playground testing:

    struct Player {
        let score: Int
    }
    

    let players1: [Player] = [.init(score: 2),
                              .init(score: 2),
                              .init(score: 3),
                              .init(score: 4)]
    let players2: [Player] = [.init(score: 2),
                              .init(score: 3),
                              .init(score: 3),
                              .init(score: 5)]
    

    let scoresExampleOne = players1.min(\.score)          // (min 2, single false)
    let scoresExampleTwo = players2.min(\.score)          // (min 2, single true)
    let scoresExampleThree = players1.minElement(\.score) // ({score 2}, single false)
    let scoresExampleFour = players2.minElement(\.score)  // ({score 2}, single true)