如何计算 Swift 数组中某个元素的出现次数? [英] How to count occurrences of an element in a Swift array?

查看:29
本文介绍了如何计算 Swift 数组中某个元素的出现次数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

提前致谢

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

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

解决方案

Swift 3 和 Swift 2:

您可以使用 [String: Int] 类型的字典来为 [String] 中的每个项目建立计数:

let arr = [FOO"、FOO"、BAR"、FOOBAR"]var 计数:[String: Int] = [:]对于 arr { 中的项目计数[项目] = (计数[项目] ?? 0) + 1}打印(计数)//[BAR:1,FOOBAR:1,FOO:2]";for (key, value) in counts {打印(\(键)出现\(值)次")}

输出:

BAR 出现 1 次FOOBAR 出现 1 次FOO 出现 2 次


Swift 4:

Swift 4 介绍 (SE-0165) 在字典查找中包含默认值的能力,并且结果值可以通过诸如 +=-= 之类的操作来改变,所以:

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

变成:

counts[item, default: 0] += 1

这使得使用 forEach 在简洁的一行中完成计数操作变得容易:

let arr = [FOO"、FOO"、BAR"、FOOBAR"]var 计数:[String: Int] = [:]arr.forEach { counts[$0, default: 0] += 1 }打印(计数)//[FOOBAR":1,FOO":2,BAR":1]";


Swift 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 }打印(计数)//[BAR":1,FOOBAR":1,FOO":2]

或者使用默认参数:

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

最后,您可以将其作为 Sequence 的扩展,以便可以在任何包含 Hashable 项目(包括 Array)的 Sequence 上调用它ArraySliceStringString.SubSequence:

extension Sequence where Element: Hashable {var 直方图:[元素:Int] {return self.reduce(into: [:]) { counts, elem in counts[elem, default: 0] += 1 }}}

这个想法是从这个问题借来的,尽管我将其更改为计算属性.感谢@LeoDabus 建议扩展 Sequence 而不是 Array 以获取其他类型.

示例:

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]

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

How can I count the occurrences of foo, bar and foobar without knowing what they are in advance?

解决方案

Swift 3 and Swift 2:

You can use a dictionary of type [String: Int] to build up counts for each of the items in your [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:

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:

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:

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


Swift 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:

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]

Or using the default parameters:

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

Finally you can make this an extension of Sequence so that it can be called on any Sequence containing Hashable items including Array, ArraySlice, String, and String.SubSequence:

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

This idea was borrowed from this question although I changed it to a computed property. Thanks to @LeoDabus for the suggestion of extending Sequence instead of Array to pick up additional types.

Examples:

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]

这篇关于如何计算 Swift 数组中某个元素的出现次数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆