Reputation: 63
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.
Upvotes: 0
Views: 176
Reputation: 236420
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)
Upvotes: 3
Reputation:
Leo's answer is good, but it's a special case of this extremum
method.
public extension Sequence {
/// The first element of the sequence.
/// - Note: `nil` if the sequence is empty.
var first: Element? {
var iterator = makeIterator()
return iterator.next()
}
/// - Parameters:
/// - comparable: The property to compare.
/// - areSorted: Whether the elements are in order, approaching the extremum.
func extremum<Comparable: Swift.Comparable>(
comparing comparable: (Element) throws -> Comparable,
areSorted: (Comparable, Comparable) throws -> Bool
) rethrows -> Extremum<Element>? {
try first.map { first in
try dropFirst().reduce(into: .init(value: first, count: 1)) {
let comparables = (try comparable($0.value), try comparable($1))
if try areSorted(comparables.0, comparables.1) {
$0 = .init(value: $1, count: 1)
} else if (comparables.0 == comparables.1) {
$0.count += 1
}
}
}
}
/// - throws: `Extremum<Element>.UniqueError`
func uniqueMin<Comparable: Swift.Comparable>(
comparing comparable: (Element) throws -> Comparable
) throws -> Extremum<Element> {
typealias Error = Extremum<Element>.UniqueError
guard let extremum = try extremum(comparing: comparable, areSorted: >)
else { throw Error.emptySequence }
guard extremum.count == 1
else { throw Error.notUnique(extremum) }
return extremum
}
}
public struct Extremum<Value> {
enum UniqueError: Swift.Error {
case emptySequence
case notUnique(Extremum)
}
var value: Value
var count: Int
}
Upvotes: 0
Reputation: 130122
func isSingleLowestValue(scores: [Int]) -> Bool {
guard let min = scores.min() else { return false }
let minCount = scores.lazy.filter { $0 == min }.count
return minCount == 1
}
Upvotes: 1