Limiter les résultats d'un filter de tableau Swift à X pour des performances

J'ai environ 2000 éléments dans mon tableau, et quand il est filtré, je voudrais terminer le filtrage dès que j'ai 5 éléments dans mon tableau filtré.

Actuellement c'est:

providerArray.filter({($0.lowercased().range(of:((row.value as? Ssortingng)?.lowercased())!) != nil)}) 

qui peut returnner jusqu'à 2000 résultats ce qui est un gaspillage de traitement, et le time.

Pour être plus clair, j'ai besoin d'une solution qui équivaut à limiter les résultats du filter comme je le peux avec les récupérations de coreData [request setFetchLimit:5];

La solution la plus rapide en termes de time d'exécution semble être une boucle explicite qui ajoute des éléments correspondants jusqu'à ce que la limite soit atteinte:

 extension Sequence { public func filter(where isIncluded: (Iterator.Element) -> Bool, limit: Int) -> [Iterator.Element] { var result : [Iterator.Element] = [] result.reserveCapacity(limit) var count = 0 var it = makeIterator() // While limit not reached and there are more elements ... while count < limit, let element = it.next() { if isIncluded(element) { result.append(element) count += 1 } } return result } } 

Exemple d'utilisation:

 let numbers = Array(0 ..< 2000) let result = numbers.filter(where: { $0 % 3 == 0 }, limit: 5) print(result) // [0, 3, 6, 9, 12] 

Vous pouvez également utiliser .lazy pour booster un peu les performances:

 let numbers: [Int] = Array(0 ..< 2000) let result: AnySequence = numbers .lazy .filter { print("Calling filter for: \($0)") return ($0 % 3) == 0 } .prefix(5) print(Array(result)) 

Cela appellera la fonction de filter seulement pour les 15 premières valeurs (jusqu'à ce qu'il trouve 5 qui passent le filter).

Vous pouvez maintenant vous concentrer sur l'amélioration des performances du filter lui filter même. Par exemple en mettant en cache des valeurs. Vous n'avez pas à le faire, mais si certaines valeurs ne cessent de se répéter, cela peut améliorer considérablement les performances.

 let numbers: [Int] = Array(0 ..< 2000) var filterCache: [Int: Bool] = [:] let result: AnySequence = numbers .lazy .filter { if let cachedResult = filterCache[$0] { return cachedResult } print("Calling filter for: \($0)") let result = (($0 % 3) == 0) filterCache[$0] = result return result } .prefix(5) print(Array(result)) 

Vous pouvez appliquer cette méthode directement à votre fonction.

Notez également que pour améliorer les performances, vous devez:

  • save ((row.value as? Ssortingng)?.lowercased())! dans une variable locale car elle est exécutée plusieurs fois

  • simplifier l'expression en utilisant les options:

  let result: AnySequence = providerArray .lazy .filter { $0.range(of: row.value as! Ssortingng, options: [.caseInsensitive]) != nil } .prefix(5)