Arrays Swift数组最大值及其索引的高效算法

Arrays Swift数组最大值及其索引的高效算法,arrays,swift,max,Arrays,Swift,Max,我已经编写了一个算法,用于在Swift数组中查找最大值及其索引。这是受到Matlab和Octave中的“max.m”函数的启发 这里的专家们能提出一种改进算法速度的方法吗?我的意思是,它是否可以变得更快,或者您认为这是一种适用于大型阵列(有时是15000个样本)的合理方法 public func max(y:[Double])->(Int,Double){ 让inLen=y.count var out=Double() var outp=Int() if(1==inLen){//if只有一个元素

我已经编写了一个算法,用于在Swift数组中查找最大值及其索引。这是受到Matlab和Octave中的“max.m”函数的启发

这里的专家们能提出一种改进算法速度的方法吗?我的意思是,它是否可以变得更快,或者您认为这是一种适用于大型阵列(有时是15000个样本)的合理方法

public func max(y:[Double])->(Int,Double){
让inLen=y.count
var out=Double()
var outp=Int()
if(1==inLen){//if只有一个元素
out=y[0]
输出=0
}else如果(0==inLen){//如果没有元素
out=-1
输出=-1
}否则{
out=y[0]
输出=0
对于1…inLen-1中的ii{
如果(输出代码)检查原始代码
这里是我将要做的更改。所有这些都有点粗糙(我没有检查是否所有这些都可以编译),但会让您走上正确的轨道

  • 使代码通用

    public func max (y: [Double]) -> (Int, Double) {
    
    变成:

    public func max<T: Comparable>(y: [T]) -> (Int, T) {
    
  • 向结果中添加关键字:

    public func max<T: Comparable>(_ array: [T]) -> (index: Int, value: T) {
    
  • 内联不必要的变量
    inLen
    ,或者至少更好地命名它,就像
    count

  • out
    outp
    重命名为更好的名称,例如
    maxValue
    maxIndex

  • extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element) {
            if count == 0 { return (index: -1, value: -1) } 
            if count == 1 { return (index: 0, value: self[0]) }
    
            var maxValue = self[0]
            var maxIndex = 0
            for i in 1...count-1 {
                if (maxValue < self[i]) {
                    maxValue = self[i]
                    maxIndex = i
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
  • 不要在Swift中使用yoda比较。
    =
    不是Swift中的表达式,因此不会意外导致if语句中的赋值而不是比较。这会触发编译器错误。此外,请忽略

    if (1 == count) {
    
    应该是

    if (count == 1) {
    
  • 在if语句中省略不需要的并列关系:

    if count == 1 {
    
  • 以更合理的顺序重新排列计数检查。而不是1,0,1+,将其排序为0,1,1+

  • 尽早返回,而不是使用if/elseif/else跳过代码块以获得公共返回。而不是:

    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element) {
            var maxValue = Double()
            var maxIndex = Int()
    
            if count == 0 { // if no elements
                maxValue = -1
                maxIndex = -1
            } else if count == 1 { // if only one element
                maxValue = self[0]
                maxIndex = 0
            } else {
                maxValue = self[0]
                maxIndex = 0
                for i in 1...inLen-1 {
                    if (maxValue < self[i]){
                        maxValue = self[i]
                        maxIndex = i
                    }
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
  • 避免重写诸如
    1…x-1等内容,而是使用
    。您可以使用
    来自加速框架的函数。vDSP函数使用
    (aka
    UInt
    )用于数组计数和索引,因此必须转换 索引到
    Int
    以实现快速互操作性

    import Accelerate
    
    let array: [Double] = ...
    
    var elem = 0.0
    var vdspIndex: vDSP_Length = 0
    vDSP_maxviD(array, 1, &elem, &vdspIndex, vDSP_Length(array.count))
    let idx = Int(vdspIndex)
    
    print("max:", elem, "at index:", idx)
    
    这比你的显式计算快了大约5倍
    15000元素数组的循环(在发布模式下编译的iMac上).

    你在找代码审查吗?因为这段代码中有很多地方可以改进。嗨,Alexander——是的,我想是的!我应该在代码审查中发布它吗?在这里很好。我正在努力完成它,需要一段时间,有很多地方需要更改。好的,谢谢Alexander!我已经完成了我的第一次尝试。性能可能是一样的,但是质量大大提高了!如果您有任何问题,请告诉我Hanks Alexander&Martin!Martin,使用vDSP_maxviD函数,似乎我必须将idx转换为Int(idx)如果我想用它来获取另一个数组的元素,或者如果我需要向它添加一个整数。我在这里读到,特别是在循环中进行强制转换是不好的,因为它会消耗时间。如何克服idx的强制转换?@Pat:你只需将索引转换为Int一次。这与vDSP_maxviD调用相比可以忽略不计。@Pat我提供了一个包装器f或者我答案底部的代码。它使你在外部只处理好Swift类型/约定
    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element) {
            var maxValue = Double()
            var maxIndex = Int()
    
            if count == 0 { // if no elements
                maxValue = -1
                maxIndex = -1
            } else if count == 1 { // if only one element
                maxValue = self[0]
                maxIndex = 0
            } else {
                maxValue = self[0]
                maxIndex = 0
                for i in 1...inLen-1 {
                    if (maxValue < self[i]){
                        maxValue = self[i]
                        maxIndex = i
                    }
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element)? {
            var maxValue = Double()
            var maxIndex = Int()
    
            if count == 0 { return (index: -1, value: -1) } 
            if count == 1 { return (index: 0, value: self[0]) }
    
            maxValue = self[0]
            maxIndex = 0
            for i in 1...count-1 {
                if (maxValue < self[i]) {
                    maxValue = self[i]
                    maxIndex = i
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element) {
            if count == 0 { return (index: -1, value: -1) } 
            if count == 1 { return (index: 0, value: self[0]) }
    
            var maxValue = self[0]
            var maxIndex = 0
            for i in 1...count-1 {
                if (maxValue < self[i]) {
                    maxValue = self[i]
                    maxIndex = i
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
    for i in self.indicies {
    
    for (index, value) in self.enumerated() {
    
    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element)? {
            if count == 0 { return nil } 
            if count == 1 { return (index: 0, value: self[0]) }
    
            var maxValue = self[0]
            var maxIndex = 0
            for (index, value) in self.enumerated() {
                if (maxValue < value) {
                    maxValue = value
                    maxIndex = index
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element)? {
            if count == 0 { return nil } 
            if count == 1 { return (index: 0, value: self[0]) }
    
            var (maxIndex, maxValue) = (0, self[0])
            for (index, value) in self.enumerated() {
                if (maxValue < value) {
                    (maxIndex, maxValue) = (index, value)
                }
            }
            return (index: maxIndex, value: maxValue)
        }
    }
    
    extension Array where Element: Comparable {
        public func max() -> (index: Int, value: Element)? {
            if count == 0 { return nil } 
            if count == 1 { return (index: 0, value: self[0]) }
    
            var maxElement = (index: 0, value: self[0])
            for (index, value) in self.enumerated() {
                if (maxElement.value < value) { maxElement = (index, value) }
            }
            return maxElement
        }
    }
    
    let array: [Double] = [3, 4, 5, 6, 7, 8, 9, 100, 100, 11, 12, 13, 14, 15, -8, -7, -7, 99]
    
    if let (maxIndex, maxValue) = array.max() {
        print("The max element is \(maxValue) at index \(maxIndex)")
    }
    else {
        print("The array is empty, and has no max element or index.")
    }
    
    let array: [Double] = [3, 4, 5, 6, 7, 8, 9, 100, 100, 11, 12, 13, 14, 15, -8, -7, -7, 99]
    
    if let (maxIndex, maxValue) = array.enumerated.max{ $0.element < $1.element } {
        print("The max element is \(maxValue) at index \(maxIndex)")
    }
    else {
        print("The array is empty, and has no max element or index.")
    }
    
    func max(of array: [Double]) -> (index: Int, value: Double)? {
        var maxValue = Double()
        var maxIndex = vDSP_Length()
        vDSP_maxviD(array, 1, &maxValue, &maxIndex, vDSP_Length(array.count))
    
        if maxValue == -Double.infinity { return nil }
    
        return (index: Int(maxIndex), value: maxValue)
    }
    
    import Accelerate
    
    let array: [Double] = ...
    
    var elem = 0.0
    var vdspIndex: vDSP_Length = 0
    vDSP_maxviD(array, 1, &elem, &vdspIndex, vDSP_Length(array.count))
    let idx = Int(vdspIndex)
    
    print("max:", elem, "at index:", idx)