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.