如何计算Swift数组中元素的出现次数?

Ale*_*ers 47 arrays nsarray ios swift

我已经看到了一些这方面的例子,但所有这些似乎依赖于知道你想要计算哪些元素的出现次数.我的数组是动态生成的,所以我无法知道我想要计算哪个元素的出现次数(我想计算所有这些元素的出现次数).任何人都可以建议吗?

提前致谢

编辑:

也许我应该更清楚,数组将包含多个不同的字符串(例如 ["FOO", "FOO", "BAR", "FOOBAR"]

如何在不知道它们是什么的情况下计算foo,bar和foobar的出现次数?

vac*_*ama 97

Swift 3和Swift 2:

您可以使用类型字典为您的[String: Int]每个项目建立计数[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)")
}
Run Code Online (Sandbox Code Playgroud)

输出:

BAR occurs 1 time(s)
FOOBAR occurs 1 time(s)
FOO occurs 2 time(s)
Run Code Online (Sandbox Code Playgroud)

斯威夫特4:

Swift 4 引入了(SE-0165)通过字典查找包含默认值的能力,并且可以使用诸如+=和的操作来改变结果值-=,因此:

counts[item] = (counts[item] ?? 0) + 1
Run Code Online (Sandbox Code Playgroud)

变为:

counts[item, default: 0] += 1
Run Code Online (Sandbox Code Playgroud)

这样可以很容易地使用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]"
Run Code Online (Sandbox Code Playgroud)

斯威夫特4: reduce(into:_:)

Swift 4引入了一个新版本,reduce它使用一个inout变量来累积结果.使用它,计数的创建真正成为一条线:

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]
Run Code Online (Sandbox Code Playgroud)

或者使用默认参数:

let counts = arr.reduce(into: [:]) { $0[$1, default: 0] += 1 }
Run Code Online (Sandbox Code Playgroud)

最后,您可以将其作为扩展,Array以便可以在包含Hashable项目的任何数组上调用它:

extension Array where Element: Hashable {
    var histogram: [Element: Int] {
        return self.reduce(into: [:]) { counts, elem in counts[elem, default: 0] += 1 }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个想法是从这个问题借来的,虽然我把它改成了计算属性.

  • 字典查找返回一个可选值,因为该字符可能不存在于字典中.您需要打开该可选项才能使用它.在这里,我使用*nil合并运算符***??**表示如果有值则展开值,否则使用提供的默认值"0".我们第一次遇到一个字符串时,它不会出现在`count`字典中,所以`count ["FOO"]`将返回`nil`,**??**转换为'0`.下次我们遇到`"FOO"`时,`count ["FOO"]`将返回`Optional(1)`****??**将解包为`1`. (3认同)

Rub*_*ben 81

array.filter{$0 == element}.count
Run Code Online (Sandbox Code Playgroud)

  • 因为问题(至少以其当前形式)要求获取每个元素的计数.这对于一个特定元素的计数来说非常棒. (7认同)
  • 虽然这个解决方案非常优雅,但它可能效率低下,因为它会创建第二个数组,然后计算其元素.一个更有效的解决方案就是`var count = 0 array.forEach {x in if x == element {count + = 1}}` (4认同)
  • 人们为什么不认为最好的答案完全超出了我。 (3认同)
  • 为什么这个答案被投票?它根本没有回答原始问题。 (3认同)
  • 迄今为止最简洁的答案 (2认同)

Ima*_*tit 25

使用Swift 4,您可以根据需要选择以下6个Playground代码中的一个来计算阵列中可出售物品的出现次数.


#1.使用Array reduce(into:_:)Dictionary subscript(_:default:)(需要Swift 4)

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]
Run Code Online (Sandbox Code Playgroud)

#2.使用repeatElement(_:count:)函数,zip(_:_:)函数,Dictionary init(_:uniquingKeysWith:)初始化器和返回Dictionary(需要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]
Run Code Online (Sandbox Code Playgroud)

#3.使用init(grouping:by:) mapValues(_:)初始化程序并返回Dictionary元组(需要Swift 4)

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]
Run Code Online (Sandbox Code Playgroud)

#4.使用for循环并返回ainit(grouping:by:)

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)]
Run Code Online (Sandbox Code Playgroud)

#5.使用map(_:),Dictionary方法和返回subscript(_:)元组(需要基础)

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]
Run Code Online (Sandbox Code Playgroud)

#6.使用NSCountedSet,NSEnumerator并返回一个map(_:)元组(需要基金会)

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)]
Run Code Online (Sandbox Code Playgroud)

积分:

  • 很棒的答案! (2认同)

ken*_*nek 9

我更新了oisdk对Swift2的回答.

16/04/14我将此代码更新为Swift2.2

16/10/11更新为Swift3


哈希的:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Equatable:

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)]
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

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)]
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)