Saltar al contenido

Cómo contar las apariciones de un elemento en un Swift array?

Solución:

Swift 3 y Swift 2:

Puede utilizar un diccionario de tipo [String: Int] para acumular recuentos para cada uno de los elementos en su [String]:

let arr = ["FOO", "FOO", "BAR", "FOOBAR"]
var counts: [String: Int] = [:]

for item in arr 
    counts[item] = (counts[item] ?? 0) + 1


print(counts)  // "[BAR: 1, FOOBAR: 1, FOO: 2]"

for (key, value) in counts 
    print("(key) occurs (value) time(s)")

producción:

BAR occurs 1 time(s)
FOOBAR occurs 1 time(s)
FOO occurs 2 time(s)

Rápido 4:

Swift 4 introduce (SE-0165) la capacidad de incluir un valor predeterminado con una búsqueda en el diccionario, y el valor resultante se puede mutar con operaciones como += y -=, asi que:

counts[item] = (counts[item] ?? 0) + 1

se convierte en:

counts[item, default: 0] += 1

Eso facilita la operación de conteo en una línea concisa usando forEach:

let arr = ["FOO", "FOO", "BAR", "FOOBAR"]
var counts: [String: Int] = [:]

arr.forEach  counts[$0, default: 0] += 1 

print(counts)  // "["FOOBAR": 1, "FOO": 2, "BAR": 1]"

Rápido 4: reduce(into:_:)

Swift 4 presenta una nueva versión de reduce que usa un inout variable para acumular los resultados. Usando eso, la creación de los recuentos realmente se convierte en una sola línea:

let arr = ["FOO", "FOO", "BAR", "FOOBAR"]
let counts = arr.reduce(into: [:])  counts, word in counts[word, default: 0] += 1 

print(counts)  // ["BAR": 1, "FOOBAR": 1, "FOO": 2]

O usando los parámetros predeterminados:

let counts = arr.reduce(into: [:])  $0[$1, default: 0] += 1 

Finalmente, puede hacer de esto una extensión de Sequence para que pueda ser invocado en cualquier Sequence conteniendo Hashable artículos que incluyen Array, ArraySlice, String, y String.SubSequence:

extension Sequence where Element: Hashable 
    var histogram: [Element: Int] 
        return self.reduce(into: [:])  counts, elem in counts[elem, default: 0] += 1 
    

Esta idea se tomó prestada de esta pregunta, aunque la cambié a una propiedad calculada. Gracias a @LeoDabus por la sugerencia de ampliar Sequence en lugar de Array para recoger tipos adicionales.

Ejemplos:

print("abacab".histogram)
["a": 3, "b": 2, "c": 1]
print("Hello World!".suffix(6).histogram)
["l": 1, "!": 1, "d": 1, "o": 1, "W": 1, "r": 1]
print([1,2,3,2,1].histogram)
[2: 2, 3: 1, 1: 2]
print([1,2,3,2,1,2,1,3,4,5].prefix(8).histogram)
[1: 3, 2: 3, 3: 2]
print(stride(from: 1, through: 10, by: 2).histogram)
[1: 1, 3: 1, 5: 1, 7: 1, 9: 1]

array.filter$0 == element.count

Con Swift 5, según sus necesidades, puede elegir uno de los 7 siguientes códigos de muestra de Playground para contar las ocurrencias de elementos hash en un array.


# 1. Utilizando Array‘s reduce(into:_:) y Dictionary‘s subscript(_:default:) subíndice

let array = [4, 23, 97, 97, 97, 23]
let dictionary = array.reduce(into: [:])  counts, number in
    counts[number, default: 0] += 1

print(dictionary) // [4: 1, 23: 2, 97: 3]

# 2. Utilizando repeatElement(_:count:) función, zip(_:_:) función y Dictionary‘s init(_:uniquingKeysWith:)inicializador

let array = [4, 23, 97, 97, 97, 23]

let repeated = repeatElement(1, count: array.count)
//let repeated = Array(repeating: 1, count: array.count) // also works

let zipSequence = zip(array, repeated)

let dictionary = Dictionary(zipSequence, uniquingKeysWith:  (current, new) in
    return current + new
)
//let dictionary = Dictionary(zipSequence, uniquingKeysWith: +) // also works

print(dictionary) // prints [4: 1, 23: 2, 97: 3]

# 3. Usando un Dictionary‘s init(grouping:by:) inicializador y mapValues(_:) método

let array = [4, 23, 97, 97, 97, 23]

let dictionary = Dictionary(grouping: array, by:  $0 )

let newDictionary = dictionary.mapValues  (value: [Int]) in
    return value.count


print(newDictionary) // prints: [97: 3, 23: 2, 4: 1]

# 4. Usando un Dictionary‘s init(grouping:by:) inicializador y map(_:) método

let array = [4, 23, 97, 97, 97, 23]

let dictionary = Dictionary(grouping: array, by:  $0 )

let newArray = dictionary.map  (key: Int, value: [Int]) in
    return (key, value.count)


print(newArray) // prints: [(4, 1), (23, 2), (97, 3)]

# 5. Usando un bucle for y Dictionary‘s subscript(_:) subíndice

extension Array where Element: Hashable 

    func countForElements() -> [Element: Int] 
        var counts = [Element: Int]()
        for element in self 
            counts[element] = (counts[element] ?? 0) + 1
        
        return counts
    



let array = [4, 23, 97, 97, 97, 23]
print(array.countForElements()) // prints [4: 1, 23: 2, 97: 3]

# 6. Utilizando NSCountedSet y NSEnumerator‘s map(_:) método (requiere Fundación)

import Foundation

extension Array where Element: Hashable 

    func countForElements() -> [(Element, Int)] 
        let countedSet = NSCountedSet(array: self)
        let res = countedSet.objectEnumerator().map  (object: Any) -> (Element, Int) in
            return (object as! Element, countedSet.count(for: object))
        
        return res
    



let array = [4, 23, 97, 97, 97, 23]
print(array.countForElements()) // prints [(97, 3), (4, 1), (23, 2)]

# 7. Utilizando NSCountedSet y AnyIterator (requiere Fundación)

import Foundation

extension Array where Element: Hashable 

    func counForElements() -> Array<(Element, Int)> 
        let countedSet = NSCountedSet(array: self)
        var countedSetIterator = countedSet.objectEnumerator().makeIterator()
        let anyIterator = AnyIterator<(Element, Int)> 
            guard let element = countedSetIterator.next() as? Element else  return nil 
            return (element, countedSet.count(for: element))
        
        return Array<(Element, Int)>(anyIterator)
    



let array = [4, 23, 97, 97, 97, 23]
print(array.counForElements()) // [(97, 3), (4, 1), (23, 2)]

Créditos:

  • Modismos rápidos
  • genérico en la colección, usando el diccionario

Si eres capaz, eres capaz de dejar un enunciado acerca de qué te ha parecido este post.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *