ios 如何计算 Swift 数组中某个元素的出现次数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30545518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to count occurrences of an element in a Swift array?
提问by Alex Chesters
I've seen a few examples of this but all of those seem to rely on knowing which element you want to count the occurrences of. My array is generated dynamically so I have no way of knowing which element I want to count the occurrences of (I want to count the occurrences of all of them). Can anyone advise?
我已经看到了一些这样的例子,但所有这些似乎都依赖于知道你想要计算哪个元素的出现次数。我的数组是动态生成的,所以我无法知道要计算哪个元素的出现次数(我想计算所有元素的出现次数)。任何人都可以建议吗?
Thanks in advance
提前致谢
EDIT:
编辑:
Perhaps I should have been clearer, the array will contain multiple different strings (e.g.
["FOO", "FOO", "BAR", "FOOBAR"]
也许我应该更清楚,数组将包含多个不同的字符串(例如
["FOO", "FOO", "BAR", "FOOBAR"]
How can I count the occurrences of foo, bar and foobar without knowing what they are in advance?
如何在不知道它们是什么的情况下计算 foo、bar 和 foobar 的出现次数?
回答by vacawama
Swift 3 and Swift 2:
斯威夫特 3 和斯威夫特 2:
You can use a dictionary of type [String: Int]
to build up counts for each of the items in your [String]
:
您可以使用类型字典为您的 中的[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)")
}
output:
输出:
BAR occurs 1 time(s)
FOOBAR occurs 1 time(s)
FOO occurs 2 time(s)
Swift 4:
斯威夫特 4:
Swift 4 introduces (SE-0165)the ability to include a default value with a dictionary lookup, and the resulting value can be mutated with operations such as +=
and -=
, so:
Swift 4引入了 (SE-0165)在字典查找中包含默认值的能力,并且结果值可以使用+=
and等操作进行变异-=
,因此:
counts[item] = (counts[item] ?? 0) + 1
becomes:
变成:
counts[item, default: 0] += 1
That makes it easy to do the counting operation in one concise line using forEach
:
这使得使用forEach
以下命令在一行简洁的代码中轻松完成计数操作:
let arr = ["FOO", "FOO", "BAR", "FOOBAR"]
var counts: [String: Int] = [:]
arr.forEach { counts[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]
, default: 0] += 1 }
print(counts) // "["FOOBAR": 1, "FOO": 2, "BAR": 1]"
Swift 4: reduce(into:_:)
斯威夫特 4: reduce(into:_:)
Swift 4 introduces a new version of reduce
that uses an inout
variable to accumulate the results. Using that, the creation of the counts truly becomes a single line:
Swift 4 引入了一个新版本,reduce
它使用inout
变量来累积结果。使用它,计数的创建真正成为一行:
let counts = arr.reduce(into: [:]) { extension Array where Element: Hashable {
var histogram: [Element: Int] {
return self.reduce(into: [:]) { counts, elem in counts[elem, default: 0] += 1 }
}
}
[, default: 0] += 1 }
Or using the default parameters:
或者使用默认参数:
array.filter{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]
== element}.count
Finally you can make this an extension of Array
so that it can be called on any array containing Hashable
items:
最后,您可以将其作为 的扩展,Array
以便可以在任何包含Hashable
项目的数组上调用它:
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]
This idea was borrowed from this questionalthough I changed it to a computed property.
这个想法是从这个问题借来的,尽管我把它改成了一个计算属性。
回答by Ruben
let array = [4, 23, 97, 97, 97, 23]
let dictionary = Dictionary(grouping: array, by: { let array = [4, 23, 97, 97, 97, 23]
let dictionary = Dictionary(grouping: array, by: { 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]
})
let newArray = dictionary.map { (key: Int, value: [Int]) in
return (key, value.count)
}
print(newArray) // prints: [(4, 1), (23, 2), (97, 3)]
})
let newDictionary = dictionary.mapValues { (value: [Int]) in
return value.count
}
print(newDictionary) // prints: [97: 3, 23: 2, 4: 1]
回答by Imanou Petit
With Swift 5, according to your needs, you may choose one of the 7 following Playground sample codesto count the occurrences of hashable items in an array.
使用 Swift 5,您可以根据需要选择以下 7 个 Playground 示例代码之一来计算数组中可哈希项的出现次数。
#1. Using Array
's reduce(into:_:)
and Dictionary
's subscript(_:default:)
subscript
#1. 使用Array
'sreduce(into:_:)
和Dictionary
'ssubscript(_:default:)
下标
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)]
#2. Using repeatElement(_:count:)
function, zip(_:_:)
function and Dictionary
's init(_:uniquingKeysWith:)
initializer
#2. 使用repeatElement(_:count:)
function、zip(_:_:)
function 和Dictionary
的init(_:uniquingKeysWith:)
初始化程序
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)]
#3. Using a Dictionary
's init(grouping:by:)
initializer and mapValues(_:)
method
#3. 使用 aDictionary
的init(grouping:by:)
初始化程序和mapValues(_:)
方法
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
}
}
}
#4. Using a Dictionary
's init(grouping:by:)
initializer and map(_:)
method
#4. 使用 aDictionary
的init(grouping:by:)
初始化程序和map(_:)
方法
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)]
}
}
}
#5. Using a for loop and Dictionary
's subscript(_:)
subscript
#5. 使用 for 循环 andDictionary
的subscript(_:)
下标
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)]
#6. Using NSCountedSet
and NSEnumerator
's map(_:)
method (requires Foundation)
#6. 使用NSCountedSet
andNSEnumerator
的map(_:)
方法(需要 Foundation)
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)
#7. Using NSCountedSet
and AnyIterator
(requires Foundation)
#7. 使用NSCountedSet
和AnyIterator
(需要基础)
NSCountedSet* countedSet = [[NSCountedSet alloc] initWithArray:array];
for (NSString* string in countedSet)
NSLog (@"String %@ occurs %zd times", string, [countedSet countForObject:string]);
Credits:
学分:
回答by ken0nek
I updated oisdk's answerto Swift2.
我更新了oisdk 对 Swift2 的回答。
16/04/14 I updated this code to Swift2.2
16/04/14 我将此代码更新为 Swift2.2
16/10/11 updated to Swift3
16/10/11 更新到 Swift3
Hashable:
可哈希:
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]
Equatable:
等价:
freq([1, 1, 1, 2, 3, 3]) // [2: 1, 3: 2, 1: 3]
freq([true, true, true, false, true]) // [false: 1, true: 4]
Usage
用法
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)]
var occurances = ["tuples", "are", "awesome", "tuples", "are", "cool", "tuples", "tuples", "tuples", "shades"]
var dict:[String:Int] = [:]
occurances.map{
if let val: Int = dict[["tuples": 5, "awesome": 1, "are": 2, "cool": 1, "shades": 1]
] {
dict[var numberOfOccurenses = countedItems.filter(
{
if let array = ["FOO", "FOO", "BAR", "FOOBAR"]
// Merging keys with closure for conflicts
let mergedKeysAndValues = Dictionary(zip(array, repeatElement(1, count: array.count)), uniquingKeysWith: +)
// mergedKeysAndValues is ["FOO": 2, "BAR": 1, "FOOBAR": 1]
== "FOO" || public extension Sequence {
public func countBy<U : Hashable>(_ keyFunc: (Iterator.Element) -> U) -> [U: Int] {
var dict: [U: Int] = [:]
for el in self {
let key = keyFunc(el)
if dict[key] == nil {
dict[key] = 1
} else {
dict[key] = dict[key]! + 1
}
//if case nil = dict[key]?.append(el) { dict[key] = [el] }
}
return dict
}
let count = ["a","b","c","a"].countBy{ ##代码## }
// ["b": 1, "a": 2, "c": 1]
struct Objc {
var id: String = ""
}
let count = [Objc(id: "1"), Objc(id: "1"), Objc(id: "2"),Objc(id: "3")].countBy{ ##代码##.id }
// ["2": 1, "1": 2, "3": 1]
== "BAR" || ##代码## == "FOOBAR" {
return true
}else{
return false
}
}).count
] = val+1
} else {
dict[##代码##] = 1
}
}
回答by gnasher729
Use an NSCountedSet. In Objective-C:
使用 NSCountedSet。在 Objective-C 中:
##代码##I assume that you can translate this into Swift yourself.
我假设您可以自己将其翻译成 Swift。
回答by oisdk
How about:
怎么样:
##代码##It's generic, so it'll work with whatever your element is, as long as it's hashable:
它是通用的,所以它可以处理你的任何元素,只要它是可散列的:
##代码##And, if you can't make your elements hashable, you could do it with tuples:
而且,如果你不能让你的元素可散列,你可以用元组来做:
##代码##回答by EmilDo
I like to avoid inner loops and use .map as much as possible. So if we have an array of string, we can do the following to count the occurrences
我喜欢避免内部循环并尽可能多地使用 .map。因此,如果我们有一个字符串数组,我们可以执行以下操作来计算出现次数
##代码##prints
印刷
##代码##回答by user1700737
An other approach would be to use the filter method. I find that the most elegant
另一种方法是使用过滤器方法。我觉得最优雅
##代码##回答by ViciV
Swift 4
斯威夫特 4
##代码##