Limite los resultados de un filter de matriz Swift a X para el performance

Tengo alnetworkingedor de 2000 elementos en mi matriz, y cuando se filtra, me gustaría finalizar el filtrado tan pronto como tenga 5 elementos en mi matriz filtrada.

Actualmente es:

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

que puede devolver hasta 2000 resultados que son un desperdicio de procesamiento y time.

Para ser más claro, necesito una solución que sea equivalente a limitar los resultados del filter como puedo con coreData obtiene [request setFetchLimit:5];

La solución más rápida en términos de time de ejecución parece ser un ciclo explícito que agrega elementos coincidentes hasta que se alcanza el límite:

 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 } } 

Ejemplo de uso:

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

Puedes usar .lazy también aumenta el performance un poco:

 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)) 

Esto llamará a la function de filter solo para los primeros 15 valores (hasta que encuentre 5 que superen el filter).

Ahora puede concentrarse en boost el performance del filter sí mismo. Por ejemplo, almacenando valores en caching. No tiene que hacer esto, pero si algunos valores siguen repitiéndose, puede boost mucho el performance.

 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)) 

Puede aplicar este método directamente a su function.

También tenga en count que para boost el performance, debería:

  • save ((row.value as? String)?.lowercased())! en una variable local porque se ejecuta varias veces

  • simplifique la expresión usando opciones:

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