我有一个可能有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实现此结果的最佳和最有效的方法是什么?
答案 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]