Dawy
Dawy

Reputation: 946

How to find max/min value in array of struct

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

Answers (4)

Leo Dabus
Leo Dabus

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

Joakim Danielson
Joakim Danielson

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

iDevAmit
iDevAmit

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

gcharita
gcharita

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

Related Questions