我写了一个算法是Swift,用于在Swift数组中查找最大值及其索引。这是受Matlab& amp;中“max.m”功能的启发。八度。
这里的专家能否建议一种在速度方面改进算法的方法?我的意思是它可以更快地制作,或者你认为这对于大型阵列(有时是15000个样本)来说是一种合理的方法。
public func max (y: [Double]) -> (Int, Double) {
let inLen = y.count
var out = Double()
var outp = Int()
if (1 == inLen) { // if only one element
out = y[0]
outp = 0
} else if (0 == inLen) { // if no elements
out = -1
outp = -1
} else {
out = y[0]
outp = 0
for ii in 1...inLen-1 {
if (out<y[ii]){
out = y[ii]
outp = ii
}
}
}
return (outp, out)
}
// Call the function
let y: [Double] = [3, 4, 5, 6, 7, 8, 9, 100, 100, 11, 12, 13, 14, 15, -8, -7, -7, 99]
let (ind, value) = max(y: y)
print(ind) // 7
print(value) // 100.0
答案 0 :(得分:4)
以下是我要做的改变。这一切都很粗糙(如果所有这些都编译的话,我还没有检查过),但会让你走上正轨。
使代码通用
public func max (y: [Double]) -> (Int, Double) {
变为:
public func max<T: Comparable>(y: [T]) -> (Int, T) {
删除无用的参数关键字y
,并将y
重命名为有意义的内容
public func max<T: Comparable>(_ array: [T]) -> (Int, T) {
为结果添加关键字:
public func max<T: Comparable>(_ array: [T]) -> (index: Int, value: T) {
将其添加为Array
或RandomAccessCollection
的扩展程序,完全取代对参数的需求:
extension Array where Element: Comparable {
public func max() -> (index: Int, value: Element) {
// ...
}
}
内联不必要的变量inLen
,或至少更好地命名,例如count
将out
和outp
重命名为更好的内容,例如maxValue
和maxIndex
不要在Swift中使用yoda比较。 =
并不是Swift中的一个表达,所以没有风险在if语句中意外地导致赋值而不是比较。它会触发编译器错误。另外,省略
if (1 == count) {
应该是
if (count == 1) {
在if语句中省略了无用的parathesis:
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)
}
}
试试这个:
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)
}
}
现在您可以删除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)
}
}
避免重写1 ... x-1
之类的内容,使用..<
:
for in in 1 ..&lt;算{
在这种情况下,使用self.indices更好,它实现了同样的目标:
for i in self.indicies {
如果您需要两个索引以及与这些索引相关的值,请使用enumerated()
:
for (index, value) in self.enumerated() {
切勿在Swift中使用-1
和""
等标记值。我们有选择权表达缺乏价值。使用它们:
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)
}
}
现在我们正在使用元组赋值,我们可以看到我们可以将maxValue和maxIndex组合成一个元组,我们直接返回:
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.")
}
这是MartinR的方法的一个包装,以便更容易与其他Swift代码集成:
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)
}
答案 1 :(得分:3)
您可以使用vDSP_maxviD)()
来自Accelerate框架的功能。 vDSP功能使用
vDSP_Length
(又名UInt
)用于数组计数和索引,所以你必须转换
Swift互操作性的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倍 循环15,000个元素数组(在发布模式下编译的iMac上)。