找到最接近目标

时间:2018-06-01 19:18:01

标签: arrays swift

我有一个可能有1000多个元素的数组,并且我有一个动态目标数,我想获得最接近目标数的x个元素。 示例:

let targetNumber = 1000.0
let matches = 5

let array = [1000,2000,3000,4000,5000,6000,7000,8000,9000,10000,11000,12000,13000,14000,15000,16000,17000]

如果x为5,我需要像下面这样过滤结果:[1000,2000,3000,4000,5000,6000]

如果目标数量为10000,我将需要基本上反转结果,[10000,9000,8000,7000,6000,5000]

可以对数组进行排序。使用Swift实现此结果的最佳和最有效的方法是什么?

2 个答案:

答案 0 :(得分:1)

让我们定义一些测试数据。我们有一个功能:

func getClosest(count: Int, from values: [Int], to targetNumber: Int) -> [Int]

我们将测试以下内容:

let array = [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000]
print(getClosest(count: 5, from: array, to: 1000))
print(getClosest(count: 5, from: array, to: 10000))

一个简单的实现是按距离到目标数字对数组进行排序并获取前X个值:

func getClosest(count: Int, from values: [Int], to targetNumber: Int) -> [Int] {
    let getDistance: (Int) -> Int = {
        return abs(targetNumber - $0)
    }

    return Array(
        values
        .sorted { getDistance($0) < getDistance($1) }
        .prefix(count)
    )
}

性能不会很差(O(n * log(n))复杂性,排序的复杂性),但它并不是最佳的。

要真正获得良好的复杂性,我们需要使用名为Priority Queue的专用数据结构。优先级队列是存储元素的抽象数据结构的名称,并且始终可以返回优先级最低的元素。

这种结构的天真实现是:

struct PriorityQueue<Element, Priority: Comparable> {
    private var elements: [(element: Element, priority: Priority)] = []

    var isEmpty: Bool {
        return elements.isEmpty
    }

    var count: Int {
        return elements.count
    }

    mutating func insert(element: Element, priority: Priority) {
        elements.append((element: element, priority: priority))
        elements.sort { $0.priority < $1.priority }
    }

    mutating func peek() -> Element? {
        return elements.first?.element
    }

    mutating func pop() -> Element? {
        guard !isEmpty else {
            return nil
        }

        return elements.remove(at: 0).element
    }

    func getElements() -> [Element] {
        return Array(elements.map { $0.element })
    }
}

这基本上只是保持内部数组的排序,但请注意优先级队列的接口是什么样的。

然后我们可以这样实现我们的功能:

func getClosest(count: Int, from values: [Int], to targetNumber: Int) -> [Int] {
    let getDistance: (Int) -> Int = {
        return abs(targetNumber - $0)
    }

    var queue = PriorityQueue<Int, Int>()

    for value in values {
        queue.insert(element: value, priority: -getDistance(value))
        if queue.count > count {
            _ = queue.pop()
        }
    }

    return queue.getElements()
}

现在,通过优先队列的简单实现,这根本不会有助于提高复杂性,但如果我们更好地实施优先级队列,那么它将起作用。

优先级队列通常使用Heap或更具体的Fibonacci heap实现。

一旦理解了算法,实现它们并不复杂,但已经有一些实现。有关示例,请参阅Swift Algorithm Club: Heap and Priority Queue Data Structure

答案 1 :(得分:0)

试试这个,

let closestToTarget = array.filter { array.index(of: $0)! <= array.index(of: targetNumber)! && array.index(of: targetNumber)! - array.index(of: $0)! <= 5 }.reversed() as [Int]