Ich benötige häufig die Berechnung von Mittelwert und Standardabweichung für numerische Arrays. Also habe ich ein kleines Protokoll und Erweiterungen für numerische Typen geschrieben, die zu funktionieren scheinen. Ich hätte gerne Feedback, wenn etwas nicht stimmt mit dem, was ich getan habe. Insbesondere frage ich mich, ob es eine bessere Möglichkeit gibt zu überprüfen, ob der Typ als Double umgewandelt werden kann, um die asDouble Variable und den init(_:Double)
Konstruktor zu vermeiden.Swift Array Erweiterung für Standardabweichung
Ich weiß, es gibt Probleme mit Protokollen, die für Arithmetik zulassen, aber das scheint in Ordnung zu funktionieren und erspart mir, die Standardabweichungsfunktion in Klassen zu setzen, die es brauchen.
protocol Numeric {
var asDouble: Double { get }
init(_: Double)
}
extension Int: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Float: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Double: Numeric {var asDouble: Double { get {return Double(self)}}}
extension CGFloat: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Array where Element: Numeric {
var mean : Element { get { return Element(self.reduce(0, combine: {$0.asDouble + $1.asDouble})/Double(self.count))}}
var sd : Element { get {
let mu = self.reduce(0, combine: {$0.asDouble + $1.asDouble})/Double(self.count)
let variances = self.map{pow(($0.asDouble - mu), 2)}
return Element(sqrt(variances.mean))
}}
}
edit: Ich weiß, es irgendwie sinnlos ist [Int].mean
und sd
zu bekommen, aber ich könnte numerisch an anderer Stelle verwenden, so dass es für die Konsistenz ist ..
edit: wie @Severin Pappadeux darauf hingewiesen, Varianz in einer Weise ausgedrückt werden, die den Triple-Pass auf dem Array vermeidet - bedeuten dann Karte dann bedeuten. Hier ist die letzte Standardabweichung Erweiterung
extension Array where Element: Numeric {
var sd : Element { get {
let sss = self.reduce((0.0, 0.0)){ return ($0.0 + $1.asDouble, $0.1 + ($1.asDouble * $1.asDouble))}
let n = Double(self.count)
return Element(sqrt(sss.1/n - (sss.0/n * sss.0/n)))
}}
}
'Int' ist in der Regel die gleiche Größe wie' Int64' auf neueren Geräten ('> =' iPhone 5S, die die 64-Bit-Prozessor eingeführt), es sei denn, Sie arbeiten mit wirklich großen Zahlen, sollte dies kein Problem sein, aber nur wissen, dass 'init (_: Double)' kann zu einem Integer-Überlauf (Laufzeit Ausnahme) in Fällen, in denen das Element = Int 'type kann die Integer-Darstellung eines gegebenen (riesigen) 'Double'-Wertes nicht speichern. Möglicherweise kein Problem, wenn Sie Ihre Swift-Apps nur selbst verwenden, aber für den Fall, dass Sie an Kunden versenden, sollte dies im Hinterkopf behalten werden. – dfri
Ok interessant danke. Es ist unwahrscheinlich, dass ich es mit Ganzzahlen verwenden werde, und die Werte, mit denen ich arbeite, sind mit dieser App physiologisch auf <500 beschränkt. Also sollte in Ordnung sein. –
@dfri sehr nützlicher Kommentar! Ich nehme an, dass es keine Möglichkeit gibt, diese Art von Überlauf zu "fangen"? – matt