1

I have made a function that finds the closest element that is smaller and bigger from a user's input.

To manage this I've used the .last() and .first() methods.

func closestNumbers(_ column: [String], value: Int) {                           
    // Gets the closest element in array to userInput
    let userInput = value

    let rangeA = column

    let left = rangeA.last(where: { $0  <=  String(userInput)})!      // last element that is less or equal to userInput
    let right = rangeA.first(where: { $0 >= String(userInput)})!    // first element that is bigger or the same as userInput


    print(left, userInput, right)
    // prints   left <= userInput >= right
}

EXAMPLE: If the userInput would be 450 in an array of [100, 200, .... , 1000].

The print should return (400, 450, 500)

However, it returns 1000, 450, 500.

Even though I feel the logic is correct.

3
  • 2
    It's correct. In terms of String "1000" is less than "400". Just compare the integers Commented Jul 10, 2019 at 6:50
  • Why you cast your numbers in String, you should cast them in Int or Double instead. Edit: As @vadian said its most likely due to this cast Commented Jul 10, 2019 at 6:51
  • I suspected that, thanks ill try that! Commented Jul 10, 2019 at 7:03

2 Answers 2

1

You are trying to compare strings not the numbers here:

let left = rangeA.last(where: { $0  <=  String(userInput)})!
let right = rangeA.first(where: { $0 >= String(userInput)})!

This means that they will be compared in the dictionary order, or lexicographically. In dictionary order, 1000 comes before 450, so it is "less than" 450. And since 1000 is the last element in the array, it is chosen as the last one that is less than 450.

You should instead convert the array elements to Int and compare the Ints instead:

let left = rangeA.last(where: { Int($0)!  <=  userInput})!
let right = rangeA.first(where: { Int($0)! >= userInput})! 

In fact, why not just make the parameter type an [Int] instead of a [String]?

func closestNumbers(_ column: [Int], value: Int) {

Then you don't need any conversion at all.

Note that this will only work if rangeA is sorted. If rangeA is not guaranteed to be sorted, you have to sort it first.

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

1 Comment

It makes a lot more sense now, the reason why I did it like this was because the array of values I get from a csv file where it was as Strings. And I couldn't figure out how to get them as Ints. Beginner mistakes all over I guess. But thank you this cleared up a lot. Cheers all for the help!
0

The solution is to not use String but Int instead

func closestNumbers(_ column: [Int], value: Int) -> (Int?, Int, Int?) {                           
    return (column.last(where: { $0  <  value}), value, column.first(where: { $0 > value}))
}

let arr = Array(0...20).map { $0 * 50 }

print(closestNumbers(arr, value: 450))

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.