2015-04-12 15 views

Odpowiedz

21

Każda metoda musi iterować wszystkie elementy aż inny element znaleziono:

func allEqualUsingLoop<T : Equatable>(array : [T]) -> Bool { 
    if let firstElem = array.first { 
     for elem in array { 
      if elem != firstElem { 
       return false 
      } 
     } 
    } 
    return true 
} 

Zamiast wyraźnego pętli można użyć funkcję:

func allEqualUsingContains<T : Equatable>(array : [T]) -> Bool { 
    if let firstElem = array.first { 
     return !contains(array, { $0 != firstElem }) 
    } 
    return true 
} 

Jeśli elementy tablicy są Hashable (takie jak Int), możesz wtedy utworzyć Set (dostępny od Swift 1.2) z elementów tablicy i sprawdzić, czy ma dokładnie jeden element.

func allEqualUsingSet<T : Hashable>(array : [T]) -> Bool { 
    let uniqueElements = Set(array) 
    return count(uniqueElements) <= 1 
} 

Szybki test analiza porównawcza wykazała, że ​​„zawiera” metoda jest znacznie szybsza niż „Set” metody dla tablicy 1.000.000 liczb całkowitych, w szczególności jeśli elementy są nie wszystkie równe. Ma to sens, ponieważ powraca wkrótce , gdy zostanie znaleziony element niezgodny, podczas gdy Set(array) zawsze przechodzi przez całą tablicę.

Również metody "zawiera" są równie szybkie lub nieco szybsze od jawnej pętli.

Oto prosty kod testu porównawczego. Oczywiście wyniki mogą się różnić z rozmiarem macierzy, liczbą różnych elementów i typem danych elementów.

func measureExecutionTime<T>(title: String, @noescape f : (() -> T)) -> T { 
    let start = NSDate() 
    let result = f() 
    let end = NSDate() 
    let duration = end.timeIntervalSinceDate(start) 
    println("\(title) \(duration)") 
    return result 
} 

var array = [Int](count: 1_000_000, repeatedValue: 1) 
array[500_000] = 2 

let b1 = measureExecutionTime("using loop ") { 
    return allEqualUsingLoop(array) 
} 

let b2 = measureExecutionTime("using contains") { 
    allEqualUsingContains(array) 
} 

let b3 = measureExecutionTime("using set  ") { 
    allEqualUsingSet(array) 
} 

Wyniki (pro, konfiguracji Release MacBook):

 
using loop  0.000651001930236816 
using contains 0.000567018985748291 
using set  0.0344770550727844 

Z array[1_000] = 2 wyniki są

 
using loop  9.00030136108398e-06 
using contains 2.02655792236328e-06 
using set  0.0306439995765686 

Aktualizacja Swift 2/Xcode 7: Z powodu różnych zmian w składni Swift Funkcja jest teraz zapisana jako

func allEqual<T : Equatable>(array : [T]) -> Bool { 
    if let firstElem = array.first { 
     return !array.dropFirst().contains { $0 != firstElem } 
    } 
    return true 
} 

Ale teraz można również zdefiniować jako metodę rozszerzenia dla tablic:

extension Array where Element : Equatable { 
    func allEqual() -> Bool { 
     if let firstElem = first { 
      return !dropFirst().contains { $0 != firstElem } 
     } 
     return true 
    } 
} 

print([1, 1, 1].allEqual()) // true 
print([1, 2, 1].allEqual()) // false 
+0

próbował to samo ... kompilator sprawdzane ;-) – Antonio

+0

@Antonio: Ok dzięki! –

+0

Jeśli jesteś zainteresowany innym, który możesz wypróbować, możesz użyć 'equal' i' Repeat': 'array.first.map {equal (array, Repeat (count: array.count, repeatValue: $ 0))} ?? true' (jest wolniej) –

Powiązane problemy