Using Swift, I am trying to workout a complex array filter or sort and I am stuck. My array of integers can contain between 1 and 7 elements. Given a certain integer value (say X) which is not in the array, I would like to find the array element that gives the smallest difference between itself and X.
答案 0 :(得分:33)
在 Swift 2 中,您可以将其作为具有功能风格的“单行” 编程:
let numbers = [ 1, 3, 7, 11]
let x = 6
let closest = numbers.enumerate().minElement( { abs($0.1 - x) < abs($1.1 - x)} )!
print(closest.element) // 7 = the closest element
print(closest.index) // 2 = index of the closest element
enumerate()
与所有数组元素一起迭代
相应的索引,minElement()
返回“最小”
关于封闭的(index, element)
对。
闭包比较差值的绝对值
要x
的两个元素。
(这里假设数组不为空,因此minElement()
不会返回nil
。)
请注意,这可能不是大型阵列的最快解决方案, 因为(几乎)全部计算两次绝对差值 数组元素。但是对于小阵列而言,这无关紧要。
Swift 3 :
let numbers = [ 1, 3, 7, 11]
let x = 6
let closest = numbers.enumerated().min( by: { abs($0.1 - x) < abs($1.1 - x) } )!
print(closest.element) // 7
print(closest.offset) // 2
可以在编辑历史记录中找到 Swift 1.2 版本。
答案 1 :(得分:3)
Swift 4.2
您可以使用first(where:)
和firstIndex(where:)
数组方法。
假设numbers
数组已排序:
let numbers = [1, 3, 7, 11]
let x = 6
let index = numbers.firstIndex(where: { $0 >= x })!
let result = numbers.first(where: { $0 >= x })!
print(index, result) // 2 7
答案 2 :(得分:2)
另一种选择是使用reduce
方法
let numbers = [1, 3, 7, 11]
let x = 11
let result = numbers.reduce(numbers.first!) { abs($1 - x) < abs($0 - x) ? $1 : $0 }
如果你想避免重复计算绝对值,你可以先将每个数组元素映射到它与输入数字的绝对差值,然后找到最小值。
let numbers = [1, 3, 7, 11]
let x = 11
if let (index, _) = numbers.map({ abs($0 - x) }).enumerate().minElement({ $0.1 < $1.1 }) {
let result = numbers[index]
}
答案 3 :(得分:1)
Loop through the values in your array, calculate the abs() difference, compare it to a running 'currentSmallestDifference' variable, if the current difference is smaller than that then overwrite it with the new value, at the same time keep a record of the array index...
int currentSmallestDifference = int.max(); //largest value defined by the int type, this way the first difference in the loop will never be larger than this
int index = -1;
for(int i = 0, i < array.size(), i++){
if( abs(array(i) - X) < currentSmallestDifference){
currentSmallestDifference = abs(array(i) - X);
index = i;
}
}
This solves it in O(n).
But if the array was already sorted (O(nlog(n)), you could then do a O(log(n)) binary search for X in the array and find the closest value to it. No need to use abs() at all in that case... just comparisons
But for array sizes 1 to 7, algorithmic complexity isn't really a factor.
In fact for array size 1, the question isn't even a factor (?!?)
Update>> Just realised the title said smallest positive difference.. So just ditch all the abs() stuff and make sure (array(i) - X) is in the correct sign/direction.
答案 4 :(得分:1)
将其包装成扩展名:
extension Sequence where Iterator.Element: SignedNumeric & Comparable {
/// Finds the nearest (offset, element) to the specified element.
func nearestOffsetAndElement(to toElement: Iterator.Element) -> (offset: Int, element: Iterator.Element) {
guard let nearest = enumerated().min( by: {
let left = $0.1 - toElement
let right = $1.1 - toElement
return abs(left) <= abs(right)
} ) else {
return (offset: 0, element: toElement)
}
return nearest
}
func nearestElement(to element: Iterator.Element) -> Iterator.Element {
return nearestOffsetAndElement(to: element).element
}
func indexOfNearestElement(to element: Iterator.Element) -> Int {
return nearestOffsetAndElement(to: element).offset
}
}
答案 5 :(得分:0)
这里是执行单个循环以计算最接近的正值的方法。不是单线的。但仍然有效
let values = [1, 4, 9, 3, 8, 2, 11]
let x = 8
func closestPositiveValue(from array: [Int], value: Int) -> (Int, Int) { // -> (value, difference)
var (val, dif): (Int?, Int?) = (nil, nil)
for index in 0..<array.count {
if x <= array[index] {
var difference = x - array[index]
if difference < 0 {
difference = array[index] - x
}
if val == nil { // nil check for initial loop
(val, dif) = (array[index], difference)
} else {
if difference < dif! {
(val, dif) = (array[index], difference)
}
}
}
}
return (val ?? 0, dif ?? 0) // defaults to first item in array if there is no closest positive number
}
print(closestPositiveValue(from: values, value: x)) // prints (8, 0)
答案 6 :(得分:0)
基于Martin R不久前的正确答案,这是我一直在使用的便捷扩展。目前在Swift 5中。
extension Array where Element: (Comparable & SignedNumeric) {
func nearest(to value: Element) -> (offset: Int, element: Element)? {
self.enumerated().min(by: {
abs($0.element - value) < abs($1.element - value)
})
}
}
用法:
let numbers = [ 1, 3, 7, 11]
let x = 6
if let closest = numbers.nearest(to: x)
print(closest)
}
// prints (offset: 2, element: 7)