I have an array that I populate from firestore that uses a struct. Is there a way to count the number of times there is a matching string for the productName var.
This is my struct...
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
}
This is what's in my VC, I populate this from firestore and then want to count matching strings in productName
var playerStock: [PlayerStock] = []
Is there a way to do this without using a for loop?
Strings I'd like to count in productName include "smartphone"
or "laptop"
I want to store the matching total count as an int like this:
var smartphoneTotal =
var laptopTotal =
etc etc..
I've tried using filters and compact map but can't find anything that works, I think its because the array is multidimensional or because its using a dictionary?
Pretty noob here so any help appreciated!
CodePudding user response:
First group the array by productName
let groupedProducts = Dictionary.init(grouping: playerStock, by: \.productName)
you'll get
["smartphone":[PlayerStock(..), PlayerStock(..), PlayerStock(..)],
"laptop":[PlayerStock(..), PlayerStock(..)]
then map the values to their amount of items
.mapValues(\.count)
The result is
["smartphone":3, "laptop":2]
CodePudding user response:
If you want to use filter, something like this should work with your struct:
var laptopTotal = playerStock.filter { $0.productName == "laptop" }.count
CodePudding user response:
This may help
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
If you really want a functional "no for-loops" version, and if you mean you want to find things that contain your search terms, then:
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))
}
}