4

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?

6
  • 1
    What is a sin array? Commented Dec 3, 2020 at 16:22
  • @matt probably meant "in array" Commented Dec 3, 2020 at 16:24
  • 2
    Matt, obviously it's an array of the misdeeds a given developer has committed. :) Commented Dec 3, 2020 at 16:26
  • Yes, "in array" it was typo Commented Dec 3, 2020 at 16:26
  • What does it mean to find "max values for both x and y". Do you want to find a single record that has both the largest x and y value? What if one record has the max x value and a different record has the max y value? You have to define a programming problem before you can figure out how to implement a solution. Commented Dec 3, 2020 at 16:33

4 Answers 4

5

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)

Sign up to request clarification or add additional context in comments.

Comments

5

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

Comments

2

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)) }
}

Comments

1

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.