Home > Mobile >  Count string elements in an array in a multidimensional array
Count string elements in an array in a multidimensional array

Time:04-01

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))
    }
}
  • Related