统计多维数组中数组中的字符串元素

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