Swift: проверьте, какое значение в NSArray ближе всего к другому заданному значению

Допустим, у меня есть массив

var values:[CGFloat] = [-12.0, 450, 300]

Мне нужно выяснить, какое из этих чисел ближе всего к заданному значению, скажем

var givenValue:CGFloat = 64

Есть ли эффективный способ узнать, какой объект в массиве ближе всего к 64?
Я знаю, что вы можете сделать что-то вроде этого:

if abs(values[0] - 64) < abs(values[1] - 64) && abs(values[0] - 64) < abs(values[2] - 64) {
    println("values[0] is the closest to 64)
}

Но это приведет к нескольким операторам if и кажется неэффективным.

Кто-нибудь знает лучший способ сделать это? В этом примере мне понадобится значение в массиве, а также какой объектный индекс в массиве.


person George Poulos    schedule 05.03.2015    source источник
comment
Оптимизированное решение с использованием функций более высокого порядка: проверьте это: stackoverflow.com/a/62159057/6694025   -  person Abhi    schedule 02.06.2020


Ответы (3)


Сохраните minimumDifference как переменную.

Затем повторите массив. Каждый раз сравнивайте разницу в значении из массива с минимальной разницей.

Если новая разница меньше, замените минимальную разницу.

В конце массива у вас будет минимальная разница.

Это то же самое, что найти наибольшее значение, наименьшее значение и т. д.

person Fogmeister    schedule 05.03.2015

Для завершения я опубликую свой окончательный код, который решил эту проблему.

    //Array to hold dist. of visible cell to pt. 64
    var distancesToTop = [CGFloat]()

    //Array of visible cell indexPaths
    var indexPaths = tableView.indexPathsForVisibleRows()!

    for visibleCell in tableView.visibleCells() { //for each visible cell...

        //Append distance to 64 to the array
        distancesToTop.append(abs((visibleCell.frame.minY - tableView.contentOffset.y) - 64))

    }

    //Find the lowest of those values
    let numMin = distancesToTop.reduce(CGFloat.max, { min($0, $1) })

    //Determine the objectForIndexPath that the minimum number was in
    let num = find(distancesToTop, numMin)!
person George Poulos    schedule 05.03.2015

В Swift 4.2 это можно сделать с помощью методов массива first(where:) и last(where:). Имейте в виду, что приведенный ниже пример кода имеет небезопасное разыменование необязательных значений и завершится ошибкой, если givenValue находится за пределами диапазона массива values.

    func findClosest(_ values: [CGFloat], _ givenValue: CGFloat) -> CGFloat {

        let sorted = values.sorted()

        let over = sorted.first(where: { $0 >= givenValue })!
        let under = sorted.last(where: { $0 <= givenValue })!

        let diffOver = over - givenValue
        let diffUnder = givenValue - under

        return (diffOver < diffUnder) ? over : under
    }

    let values:[CGFloat] = [-12.0, 450, 300]

    print(findClosest(values, 64.0))   // -12.0
    print(findClosest(values, 143.0))  // -12.0
    print(findClosest(values, 144.5))  // 300
person djruss70    schedule 12.08.2018
comment
Ошибка, когда одно и то же число в массиве - person Shourob Datta; 10.05.2020
comment
@ShourobDatta, можете ли вы опубликовать пример, который вызывает ошибку? - person djruss70; 12.05.2020
comment
пусть значения: [CGFloat] = [12.00, 12.00, 12.00] - person Shourob Datta; 12.05.2020
comment
@ShourobDatta, ошибка не вызвана повторяющимися значениями, но искомое значение находится за пределами диапазона массива, который не обрабатывается безопасно в этом примере кода. Я оставил код как есть, чтобы не усложнять пример, но добавил предупреждение в описание. - person djruss70; 12.05.2020