Home > Software engineering >  Pull unique items & calculations from an array in SwiftUI
Pull unique items & calculations from an array in SwiftUI

Time:10-08

I'm trying to create a Metrics view in my SwiftUI app. I'm building this so I can track my poker sessions I play. Each Session model looks like this:

struct PokerSession: Hashable, Codable, Identifiable {
var id = UUID()
let location: String
let game: String
let stakes: String
let date: Date
let profit: Int
let notes: String
let imageName: String
let startTime: Date
let endTime: Date

In my Metrics View I would like to iterate through all of the sessions which are stored in an array of type: [PokerSession] that displays a List of all the unique locations and their corresponding profit totals. This is how my code looks right now, obviously not working because I'm getting duplicate locations:

            List {
            ForEach(viewModel.sessions) { location in
                HStack {
                    Text(location.location)
                    Spacer()
                    Text("$500")
                        .bold()
                        .foregroundColor(.green)
                }
            }
            .navigationBarTitle(Text("Profit by Location"))
        }

Does anyone know how I can grab unique locations and calculate their total profit? Many thanks!

CodePudding user response:

You can generate an array of unique locations like this:

Array(Set(viewModel.sessions.map { $0.location }))

Use this in your ForEach to iterate over the location strings.

CodePudding user response:

I'd define a new type to store your totals:

struct LocationProfit: Identifiable {
    let id = UUID()
    let location: String
    let profit: Int
}

Then you can group all your sessions by location in a dictionary, transform the sessions into a sum of profits, then transform the location and profit totals into our LocationProfit structure.

let locationProfits = Dictionary(grouping: sessions) { element in
    element.location
}.mapValues { sessionsGroupedByLocation -> Int in
    sessionsGroupedByLocation
        .map { $0.profit }
        .reduce(0,  )
}.map { locationProfitPair in
    LocationProfit(location: locationProfitPair.key, profit: locationProfitPair.value)
}

Just stuff the whole conversion into your viewModel and iterate over the locationProfits in your View.

CodePudding user response:

You need to filter which will return a filtered array of your PokerSessions by location then you reduce the filtered array to get the sum of your profit like this:

viewModel.sessions.filter( { $0.location == location}).reduce(0) { $0   $1.profit})

edit with use case assuming it is in USD:

Text("$\(viewModel.sessions.filter( { $0.location == location}).reduce(0) { $0   $1.profit}))")

You could also turn it into a string by add .description to the end of it. If you only need to display the data to the user, and don't need it generally available to the app, this is the simplest way of doing it.

  • Related