Comment countr les occurrences d'un élément dans un tableau Swift?

J'en ai vu quelques exemples, mais tous semblent s'appuyer sur la connaissance de l'élément dont vous voulez countr les occurrences. Mon tableau est généré dynamicment, donc je n'ai aucun moyen de savoir quel élément je veux countr les occurrences de (je veux countr les occurrences de tous). Quelqu'un peut-il conseiller?

Merci d'avance

MODIFIER:

Peut-être que j'aurais dû être plus clair, le tableau contiendra plusieurs strings différentes (par exemple ["FOO", "FOO", "BAR", "FOOBAR"]

Comment puis-je countr les occurrences de foo, bar et foobar sans savoir ce qu'elles sont en avance?

    Swift 3 et Swift 2:

    Vous pouvez utiliser un dictionary de type [Ssortingng: Int] pour créer des counts pour chacun des éléments de votre [Ssortingng] :

     let arr = ["FOO", "FOO", "BAR", "FOOBAR"] var counts: [Ssortingng: 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)") } 

    sortie:

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

    Swift 4:

    Swift 4 introduit (SE-0165) la possibilité d'inclure une valeur par défaut avec une search de dictionary, et la valeur résultante peut être muté avec des opérations telles que += et -= , donc:

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

    devient:

     counts[item, default: 0] += 1 

    Cela rend facile de faire l'opération de comptage dans une ligne concise en utilisant forEach :

     let arr = ["FOO", "FOO", "BAR", "FOOBAR"] var counts: [Ssortingng: Int] = [:] arr.forEach { counts[$0, default: 0] += 1 } print(counts) // "["FOOBAR": 1, "FOO": 2, "BAR": 1]" 
     array.filter{$0 == element}.count 

    J'ai mis à jour la réponse d'oisdk à Swift2.

    16/04/14 J'ai mis à jour ce code à Swift2.2

    16/10/11 mis à jour à Swift3


    Aissable:

     extension Sequence where Self.Iterator.Element: Hashable { private typealias Element = Self.Iterator.Element func freq() -> [Element: Int] { return reduce([:]) { (accu: [Element: Int], element) in var accu = accu accu[element] = accu[element]?.advanced(by: 1) ?? 1 return accu } } } 

    Equitable:

     extension Sequence where Self.Iterator.Element: Equatable { private typealias Element = Self.Iterator.Element func freqTuple() -> [(element: Element, count: Int)] { let empty: [(Element, Int)] = [] return reduce(empty) { (accu: [(Element, Int)], element) in var accu = accu for (index, value) in accu.enumerated() { if value.0 == element { accu[index].1 += 1 return accu } } return accu + [(element, 1)] } } } 

    Usage

     let arr = ["a", "a", "a", "a", "b", "b", "c"] print(arr.freq()) // ["b": 2, "a": 4, "c": 1] print(arr.freqTuple()) // [("a", 4), ("b", 2), ("c", 1)] 

     for (k, v) in arr.freq() { print("\(k) -> \(v) time(s)") } // b -> 2 time(s) // a -> 4 time(s) // c -> 1 time(s) for (element, count) in arr.freqTuple() { print("\(element) -> \(count) time(s)") } // a -> 4 time(s) // b -> 2 time(s) // c -> 1 time(s) 

    Avec Swift 4, en fonction de vos besoins, vous pouvez choisir l'un des 6 codes Playground suivants pour countr les occurrences d'éléments variables dans un tableau.


    #1. Utiliser Array reduce(into:_:) et reduce(into:_:) Dictionary subscript(_:default:) (nécessite Swift 4)

     let array = [4, 23, 97, 97, 97, 23] let reducedArray = array.reduce(into: [:]) { counts, number in counts[number, default: 0] += 1 } print(reducedArray) // [4: 1, 23: 2, 97: 3] 

    # 2. Utilisation de la fonction repeatElement(_:count:) fonction zip(_:_:) , de l' init(_:uniquingKeysWith:) Dictionary init(_:uniquingKeysWith:) initializer et du renvoi d'un Dictionary (nécessite Swift 4)

     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. Utiliser un Dictionary init(grouping:by:) initializer et returnner un Array de tuples (nécessite Swift 4)

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

    # 4. Utilisation d'une boucle for et renvoi d'un Dictionary

     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] 

    # 5. Utilisation de NSCountedSet , méthode map et renvoi d'un Array de tuples (nécessite Foundation)

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

    # 6. Utiliser NSCountedSet , AnyIterator et returnner un Array de tuples (nécessite Foundation)

     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édits:

    • Idiomes rapides
    • générique sur Collection, en utilisant le dictionary

    Utilisez un NSCountedSet. En Objective-C:

     NSCountedSet* countedSet = [[NSCountedSet alloc] initWithArray:array]; for (NSSsortingng* ssortingng in countedSet) NSLog (@"Ssortingng %@ occurs %zd times", ssortingng, [countedSet countForObject:ssortingng]); 

    Je suppose que vous pouvez traduire cela en Swift vous-même.

    Que diriez-vous:

     func freq<S: SequenceType where S.Generator.Element: Hashable>(seq: S) -> [S.Generator.Element:Int] { return reduce(seq, [:]) { (var accu: [S.Generator.Element:Int], element) in accu[element] = accu[element]?.successor() ?? 1 return accu } } freq(["FOO", "FOO", "BAR", "FOOBAR"]) // ["BAR": 1, "FOOBAR": 1, "FOO": 2] 

    C'est générique, donc ça marchera avec n'importe quel élément, tant qu'il est hashable:

     freq([1, 1, 1, 2, 3, 3]) // [2: 1, 3: 2, 1: 3] freq([true, true, true, false, true]) // [false: 1, true: 4] 

    Et, si vous ne pouvez pas rendre vos éléments lavables, vous pouvez le faire avec des tuples:

     func freq<S: SequenceType where S.Generator.Element: Equatable>(seq: S) -> [(S.Generator.Element, Int)] { let empty: [(S.Generator.Element, Int)] = [] return reduce(seq, empty) { (var accu: [(S.Generator.Element,Int)], element) in for (index, value) in enumerate(accu) { if value.0 == element { accu[index].1++ return accu } } return accu + [(element, 1)] } } freq(["a", "a", "a", "b", "b"]) // [("a", 3), ("b", 2)] 

    Une autre approche consisterait à utiliser la méthode de filtrage. Je trouve que le plus élégant

     var numberOfOccurenses = countedItems.filter( { if $0 == "FOO" || $0 == "BAR" || $0 == "FOOBAR" { return true }else{ return false } }).count 

    J'aime éviter les loops internes et utiliser .map autant que possible. Donc, si nous avons un tableau de string, nous pouvons faire ce qui suit pour countr les occurrences

     var occurances = ["tuples", "are", "awesome", "tuples", "are", "cool", "tuples", "tuples", "tuples", "shades"] var dict:[Ssortingng:Int] = [:] occurances.map{ if let val: Int = dict[$0] { dict[$0] = val+1 } else { dict[$0] = 1 } } 

    imprime

     ["tuples": 5, "awesome": 1, "are": 2, "cool": 1, "shades": 1] 

    Swift 4

     let array = ["FOO", "FOO", "BAR", "FOOBAR"] // Merging keys with closure for conflicts let mergedKeysAndValues = Dictionary(zip(array, repeatElement(1, count: array)), uniquingKeysWith: +) // mergedKeysAndValues is ["FOO": 2, "BAR": 1, "FOOBAR": 1] 

    Première étape du sorting par comptage.

     var inputList = [9,8,5,6,4,2,2,1,1] var countList : [Int] = [] var max = inputList.maxElement()! // Iniate an array with specific Size and with intial value. // We made the Size to max+1 to integrate the Zero. We intiated the array with Zeros because it's Counting. var countArray = [Int](count: Int(max + 1), repeatedValue: 0) for num in inputList{ countArray[num] += 1 } print(countArray)