Reputation: 946
I have Dataset structure defined as
struct Dataset: Hashable {
var x: Double
var y: Double
}
and then array
var dataset: [Dataset]
array is filled with values and I need to find max values for both x and y struct vars. Is use of
let maxXValue = dataset.max(by: (Dataset, Dataset) throws -> Bool)
right approach and how it should look then?
Upvotes: 4
Views: 2948
Reputation: 236420
You can extend Sequence
and implement custom max and min methods to allow you to specify a keypath of a property that conform to Comparable
:
extension Sequence {
func max<T: Comparable>(_ predicate: (Element) -> T) -> Element? {
self.max(by: { predicate($0) < predicate($1) })
}
func min<T: Comparable>(_ predicate: (Element) -> T) -> Element? {
self.min(by: { predicate($0) < predicate($1) })
}
}
let points: [CGPoint] = [.init(x: 1.2, y: 3.4),
.init(x: 0.1, y: 2.2),
.init(x: 2.3, y: 1.1)]
let maxX = points.max(\.x)
let maxY = points.max(\.y)
print("maxX:", maxX ?? "nil")
print("maxY:", maxY ?? "nil")
let minX = points.min(\.x)
let minY = points.min(\.y)
print("minX:", minX ?? "nil")
print("minY:", minY ?? "nil")
This will print
maxX: (2.3, 1.1)
maxY: (1.2, 3.4)
minX: (0.1, 2.2)
minY: (2.3, 1.1)
Upvotes: 5
Reputation: 51993
If you want to get two separate variables you can use map
together with max
let maxX = dataset.map(\.x).max()
let maxY = dataset.map(\.y).max()
This will give you a tuple with the largest x and y values using reduce
and max
let maxValues: (x: Double, y: Double)
if dataset.isEmpty {
maxValues = (0, 0)
} else {
maxValues = dataset
.dropFirst()
.reduce((dataset.first!.x, dataset.first!.y)) { (max($0.0, $1.x), max($0.1, $1.y)) }
}
Upvotes: 2
Reputation: 1578
I will try to explain in more detail with an example
struct Dataset: Hashable {
var x: Double
var y: Double
}
let data1 = Dataset(x: 0.4, y: 0.2)
let data2 = Dataset(x: 0.3, y: 0.1)
let data3 = Dataset(x: 0.1, y: 0.6)
let dataArray = [data1, data2, data3]
let maxX = dataArray.max { (firstElement, secondElement) -> Bool in
return firstElement.x < secondElement.x
}
let maxY = dataArray.max { (firstElement, secondElement) -> Bool in
return firstElement.y < secondElement.y
}
print("Maximum X", maxX)
print("Maximum Y", maxY)
Upvotes: 1
Reputation: 8347
max(by:)
function will return the maximum element in the sequence, using the passed closure as the comparison between the elements.
So, you code will look like this:
let maxXValue = dataset.max { $0.x < $1.x }?.x
let maxYValue = dataset.max { $0.y < $1.y }?.y
Upvotes: 5