统计多维数组中数组中的字符串元素
Count string elements in an array in a multidimensional array
我有一个从使用结构的 firestore 填充的数组。有没有办法计算 productName var.
匹配字符串的次数
这是我的结构...
struct PlayerStock: Codable, Identifiable {
@DocumentID var id: String?
var productName: String
var qty: Int
var saleUID: String
var totalPrice: Int
var uid: String
var unitPrice: Int
}
这是我的 VC 中的内容,我从 firestore 中填充它,然后想计算 productName
中的匹配字符串
var playerStock: [PlayerStock] = []
有没有不用 for 循环的方法?
我想在 productName 中计算的字符串包括 "smartphone"
或 "laptop"
我想将匹配的总计数存储为 int,如下所示:
var smartphoneTotal =
var laptopTotal =
etc etc..
我试过使用过滤器和压缩地图,但找不到任何有用的东西,我认为这是因为数组是多维的还是因为它使用了字典?
这里是菜鸟,非常感谢您的帮助!
首先将数组按 productName
分组
let groupedProducts = Dictionary.init(grouping: playerStock, by: \.productName)
你会得到
["smartphone":[PlayerStock(..), PlayerStock(..), PlayerStock(..)],
"laptop":[PlayerStock(..), PlayerStock(..)]
然后将这些值映射到它们的项目数量
.mapValues(\.count)
结果是
["smartphone":3, "laptop":2]
这可能有帮助
let wordsToFind = ["smartphone", "laptop"]
var foundCounts: [String: Int] = [:]
for p in playerStock {
for word in wordsToFind {
if p.name.contains(word) {
foundCounts[word] = foundCounts[word, default: 0] + 1
}
}
}
foundCounts
如果您真的想要一个功能性的“无 for-loops”版本,并且如果您的意思是您想要查找包含您的搜索词的内容,那么:
let wordsToFind = ["smartphone", "laptop"]
let founds = wordsToFind.map { word -> (String, Int) in
playerStock.reduce(("", 0)) { partialResult, player in
(word, partialResult.1 + (player.name.contains(word) ? 1 : 0))
}
}
如果你想使用过滤器,像这样的东西应该适用于你的结构:
var laptopTotal = playerStock.filter { [=10=].productName == "laptop" }.count
您可以使用高阶函数 filter()
或 reduce()
。 @ShawnFrank 已经使用 filter()
给出了答案。 (已投票。)
对于少量项目,filter()
和 reduce()
之间没有太大区别。但是,对于大型数据集,过滤器会创建第二个数组,其中包含与过滤条件匹配的所有项目。数组是值类型,因此它们保存它们包含的条目的副本。这会增加进行计数所需的内存占用。 (您将拥有原始数组和包含内存中所有匹配元素的副本)。
高阶函数reduce()
的工作方式不同。它需要一个起始值(在我们的例子中从 0 开始的总数)作为结果,以及一个闭包。闭包获取当前结果,以及您正在解析的数组中的一个元素。在运行时,reduce()
函数一遍又一遍地调用您的闭包,传入您正在减少的数组中的每个元素。在对闭包的第一次调用中,它向闭包发送结果的初始值(在我们的例子中为零总数)。在对闭包的每次后续调用中,它传递前一次调用的结果。 (运行 总数,对于我们的实现。)reduce()
函数 returns 最后一次调用闭包返回的结果。
您可以使用 reduce
来计算与给定测试匹配的项目数,而无需构建临时数组。下面是使用 reduce()
的示例实现。请注意,我调整了您的 PlayerStock
类型以添加除 productName 以外的所有属性的默认值,因为我不关心这些。
// Define the PlayerStock type, but use default values for everything but `productName`
struct PlayerStock: Codable, Identifiable {
var id: String? = nil
var productName: String
var qty: Int = Int.random(in: 1...10)
var saleUID: String = ""
var totalPrice: Int = Int.random(in: 10...200)
var uid: String = ""
var unitPrice: Int = Int.random(in: 10...200)
}
// Create an array of test data
let players = [
PlayerStock(productName: "smartphone"),
PlayerStock(productName: "CD Player"),
PlayerStock(productName: "laptop"),
PlayerStock(productName: "CD Player"),
PlayerStock(productName: "smartphone"),
PlayerStock(productName: "laptop"),
PlayerStock(productName: "smartphone"),
PlayerStock(productName: "boom box"),
PlayerStock(productName: "laptop"),
PlayerStock(productName: "smartphone"),
]
/// This is a function that counts and returns the number of PlayerStock items who's productName property matches a the string nameToFind.
/// If you pass in printResult = true, it logs its result for debugging.
/// - Parameter nameToFind: The `productName` to search for
/// - Parameter inArray: The array of `PlayerStock` items to search
/// - Parameter printResult: a debugging flag. If true, the function prints the count if items to the console. Defaults to `false`
/// - Returns: The number of `PlayerStock` items that have a `productName` == `nameToFind`
@discardableResult func countPlayers(nameToFind: String, inArray array: [PlayerStock], printResult: Bool = false) -> Int {
let count = array.reduce(0, { count, item in
item.productName == nameToFind ? count+1 : count
})
if printResult {
print("Found \(count) players with productName == \(nameToFind)")
}
return count
}
let smartphoneCount = countPlayers(nameToFind: "smartphone", inArray: players, printResult: true)
let laptopCount = countPlayers(nameToFind: "laptop", inArray: players, printResult: true)
let cdPlayerCount = countPlayers(nameToFind: "CD Player", inArray: players, printResult: true)
此示例代码产生以下输出:
Found 4 players with productName == smartphone
Found 3 players with productName == laptop
Found 2 players with productName == CD Player
我有一个从使用结构的 firestore 填充的数组。有没有办法计算 productName var.
匹配字符串的次数这是我的结构...
struct PlayerStock: Codable, Identifiable {
@DocumentID var id: String?
var productName: String
var qty: Int
var saleUID: String
var totalPrice: Int
var uid: String
var unitPrice: Int
}
这是我的 VC 中的内容,我从 firestore 中填充它,然后想计算 productName
中的匹配字符串var playerStock: [PlayerStock] = []
有没有不用 for 循环的方法?
我想在 productName 中计算的字符串包括 "smartphone"
或 "laptop"
我想将匹配的总计数存储为 int,如下所示:
var smartphoneTotal =
var laptopTotal =
etc etc..
我试过使用过滤器和压缩地图,但找不到任何有用的东西,我认为这是因为数组是多维的还是因为它使用了字典?
这里是菜鸟,非常感谢您的帮助!
首先将数组按 productName
let groupedProducts = Dictionary.init(grouping: playerStock, by: \.productName)
你会得到
["smartphone":[PlayerStock(..), PlayerStock(..), PlayerStock(..)],
"laptop":[PlayerStock(..), PlayerStock(..)]
然后将这些值映射到它们的项目数量
.mapValues(\.count)
结果是
["smartphone":3, "laptop":2]
这可能有帮助
let wordsToFind = ["smartphone", "laptop"]
var foundCounts: [String: Int] = [:]
for p in playerStock {
for word in wordsToFind {
if p.name.contains(word) {
foundCounts[word] = foundCounts[word, default: 0] + 1
}
}
}
foundCounts
如果您真的想要一个功能性的“无 for-loops”版本,并且如果您的意思是您想要查找包含您的搜索词的内容,那么:
let wordsToFind = ["smartphone", "laptop"]
let founds = wordsToFind.map { word -> (String, Int) in
playerStock.reduce(("", 0)) { partialResult, player in
(word, partialResult.1 + (player.name.contains(word) ? 1 : 0))
}
}
如果你想使用过滤器,像这样的东西应该适用于你的结构:
var laptopTotal = playerStock.filter { [=10=].productName == "laptop" }.count
您可以使用高阶函数 filter()
或 reduce()
。 @ShawnFrank 已经使用 filter()
给出了答案。 (已投票。)
对于少量项目,filter()
和 reduce()
之间没有太大区别。但是,对于大型数据集,过滤器会创建第二个数组,其中包含与过滤条件匹配的所有项目。数组是值类型,因此它们保存它们包含的条目的副本。这会增加进行计数所需的内存占用。 (您将拥有原始数组和包含内存中所有匹配元素的副本)。
高阶函数reduce()
的工作方式不同。它需要一个起始值(在我们的例子中从 0 开始的总数)作为结果,以及一个闭包。闭包获取当前结果,以及您正在解析的数组中的一个元素。在运行时,reduce()
函数一遍又一遍地调用您的闭包,传入您正在减少的数组中的每个元素。在对闭包的第一次调用中,它向闭包发送结果的初始值(在我们的例子中为零总数)。在对闭包的每次后续调用中,它传递前一次调用的结果。 (运行 总数,对于我们的实现。)reduce()
函数 returns 最后一次调用闭包返回的结果。
您可以使用 reduce
来计算与给定测试匹配的项目数,而无需构建临时数组。下面是使用 reduce()
的示例实现。请注意,我调整了您的 PlayerStock
类型以添加除 productName 以外的所有属性的默认值,因为我不关心这些。
// Define the PlayerStock type, but use default values for everything but `productName`
struct PlayerStock: Codable, Identifiable {
var id: String? = nil
var productName: String
var qty: Int = Int.random(in: 1...10)
var saleUID: String = ""
var totalPrice: Int = Int.random(in: 10...200)
var uid: String = ""
var unitPrice: Int = Int.random(in: 10...200)
}
// Create an array of test data
let players = [
PlayerStock(productName: "smartphone"),
PlayerStock(productName: "CD Player"),
PlayerStock(productName: "laptop"),
PlayerStock(productName: "CD Player"),
PlayerStock(productName: "smartphone"),
PlayerStock(productName: "laptop"),
PlayerStock(productName: "smartphone"),
PlayerStock(productName: "boom box"),
PlayerStock(productName: "laptop"),
PlayerStock(productName: "smartphone"),
]
/// This is a function that counts and returns the number of PlayerStock items who's productName property matches a the string nameToFind.
/// If you pass in printResult = true, it logs its result for debugging.
/// - Parameter nameToFind: The `productName` to search for
/// - Parameter inArray: The array of `PlayerStock` items to search
/// - Parameter printResult: a debugging flag. If true, the function prints the count if items to the console. Defaults to `false`
/// - Returns: The number of `PlayerStock` items that have a `productName` == `nameToFind`
@discardableResult func countPlayers(nameToFind: String, inArray array: [PlayerStock], printResult: Bool = false) -> Int {
let count = array.reduce(0, { count, item in
item.productName == nameToFind ? count+1 : count
})
if printResult {
print("Found \(count) players with productName == \(nameToFind)")
}
return count
}
let smartphoneCount = countPlayers(nameToFind: "smartphone", inArray: players, printResult: true)
let laptopCount = countPlayers(nameToFind: "laptop", inArray: players, printResult: true)
let cdPlayerCount = countPlayers(nameToFind: "CD Player", inArray: players, printResult: true)
此示例代码产生以下输出:
Found 4 players with productName == smartphone
Found 3 players with productName == laptop
Found 2 players with productName == CD Player