Map an array with a function with two arguments - Swift - arrays

Is it possible to map an array with a function that takes in two arguments?
Something like this:
let arr = [2,5,1,4,8,4]
let bankRateArr = arr.map(BankRate.init(amount:interestRate:))
class BankRate {
let amount: Int
let interestRate: Float
init(amount: Int, interestRate: Float) {
self.amount = amount
self.interestRate = interestRate
}
}

If you want to pass the same interest rate to all values, you can do:
class BankRate: CustomStringConvertible {
let amount: Int
let interestRate: Float
init(amount: Int, interestRate: Float){
self.amount = amount
self.interestRate = interestRate
}
var description: String {
return "amount: \(amount), rate: \(interestRate)"
}
}
let arr = [2, 5, 1, 4, 8, 4]
let bankRateArr = arr.map { BankRate(amount: $0, interestRate: 0.04) }
print(bankRateArr)
Output:
[amount: 2, rate: 0.04, amount: 5, rate: 0.04, amount: 1, rate: 0.04, amount: 4, rate: 0.04, amount: 8, rate: 0.04, amount: 4, rate: 0.04]
If you want each to have their own, you can do it with tuples:
let arr2 = [(2, 0.04), (5, 0.07), (1, 0.1), (4, 0.035), (8, 0.25), (4, 0.2)]
let bankRateArr2 = arr2.map { BankRate(amount: $0.0, interestRate: Float($0.1)) }
print(bankRateArr2)
Output:
[amount: 2, rate: 0.04, amount: 5, rate: 0.07, amount: 1, rate: 0.1, amount: 4, rate: 0.035, amount: 8, rate: 0.25, amount: 4, rate: 0.2]
And thanks to Martin R, the 2nd example can be shorted a bit as:
let arr3: [(Int, Float)] = [(2, 0.04), (5, 0.07), (1, 0.1), (4, 0.035), (8, 0.25), (4, 0.2)]
let bankRateArr3 = arr3.map(BankRate.init)
print(bankRateArr3)

Assuming that you will have two separate arrays
let amounts = [2, 5, 1, 4 ,8 ,4]
let rates: [Float] = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]
you could use
let bankRates = zip(amounts, rates).map(BankRate.init)

Related

Can ForEach integrate over an array within an array?

I'm building an app that shows company "x" pay rates for different departments within the company. The problem I'm running into is being able to create a ForEach that will iterate over all the pay rate array data. Currently, when you click on "Development", "Training" or "Marketing" the pay rates that display are for "Development." The higher pay rates for "Training" and "Marketing" do not display. My model data is organized to be an array ([Dept]) of arrays ([rates]). I have not been able to find any documentation or tutorials that explain how to iterate over an array within an array.
Here is my PayRateDetailView:
struct RateDetailView: View {
var dept: Dept
var body: some View {
List {
ForEach(dept.rates) { line in
RateCardView(dept: dept)
}
}
.navigationTitle(dept.deptName)
}
}
Here is my RateCardView:
struct RateCardView: View {
var dept: Dept
var body: some View {
ForEach(dept.rates) { rate in
HStack {
Text("Year \(rate.year)")
Spacer()
Text("$ \(rate.shiftWorkerRate, specifier: "%.2f")")
Spacer()
Text("$ \(rate.managerRate, specifier: "%.2f")")
}
}
}
}
Here is my PayRateView:
struct PayRateView: View {
var depts: [Dept]
var dept: Dept
var body: some View {
List {
ForEach(depts, id: \.deptName) { name in
NavigationLink(destination:
RateCardView(dept: dept)) {
Label(name.deptName, systemImage: "person")
}
}
}
}
}
I'm thinking the answer to my problem may be in finding a better way to display my pay rate model data, but this is the structure that seems best for what I'm trying to display:
struct Dept: Identifiable {
let id: UUID
var deptName: String
var rates: [HourlyRates]
init(id: UUID = UUID(), deptName: String, rates: [HourlyRates]) {
self.id = id
self.deptName = deptName
self.rates = rates
}
}
extension Dept {
static let deptList: [Dept] = [
Dept(deptName: "Development", rates: [
HourlyRates(year: 1, shiftWorkerRate: 10, managerRate: 20),
HourlyRates(year: 2, shiftWorkerRate: 11, managerRate: 21),
HourlyRates(year: 3, shiftWorkerRate: 12, managerRate: 22),
HourlyRates(year: 4, shiftWorkerRate: 13, managerRate: 23),
HourlyRates(year: 5, shiftWorkerRate: 14, managerRate: 24),
HourlyRates(year: 6, shiftWorkerRate: 15, managerRate: 25),
HourlyRates(year: 7, shiftWorkerRate: 16, managerRate: 26)]),
Dept(deptName: "Training", rates: [
HourlyRates(year: 1, shiftWorkerRate: 12, managerRate: 22),
HourlyRates(year: 2, shiftWorkerRate: 13, managerRate: 23),
HourlyRates(year: 3, shiftWorkerRate: 14, managerRate: 24),
HourlyRates(year: 4, shiftWorkerRate: 15, managerRate: 25),
HourlyRates(year: 5, shiftWorkerRate: 16, managerRate: 26),
HourlyRates(year: 6, shiftWorkerRate: 17, managerRate: 27),
HourlyRates(year: 7, shiftWorkerRate: 18, managerRate: 28)]),
Dept(deptName: "Marketing", rates: [
HourlyRates(year: 1, shiftWorkerRate: 12, managerRate: 22),
HourlyRates(year: 2, shiftWorkerRate: 13, managerRate: 23),
HourlyRates(year: 3, shiftWorkerRate: 14, managerRate: 24),
HourlyRates(year: 4, shiftWorkerRate: 15, managerRate: 25),
HourlyRates(year: 5, shiftWorkerRate: 16, managerRate: 26),
HourlyRates(year: 6, shiftWorkerRate: 17, managerRate: 27),
HourlyRates(year: 7, shiftWorkerRate: 18, managerRate: 28)])
]
}
struct HourlyRates: Identifiable {
let id: UUID
var year: Int
var shiftWorkerRate: Double
var managerRate: Double
init(id: UUID = UUID(), year: Int, shiftWorkerRate: Double, managerRate: Double) {
self.id = id
self.year = year
self.shiftWorkerRate = shiftWorkerRate
self.managerRate = managerRate
}
}
All works well for me, without using the RateDetailView that you call PayRateDetailView,
and minor mods in PayRateView.
Here is my test code, that shows the "Development", "Training" and "Marketing" pay rates are displayed as expected.
struct ContentView: View {
var body: some View {
NavigationStack { // <-- here
PayRateView()
}
}
}
struct RateCardView: View {
var dept: Dept
var body: some View {
ForEach(dept.rates) { rate in
HStack {
Text("Year \(rate.year)")
Spacer()
Text("$ \(rate.shiftWorkerRate, specifier: "%.2f")")
Spacer()
Text("$ \(rate.managerRate, specifier: "%.2f")")
}
}
}
}
struct PayRateView: View {
var depts: [Dept] = Dept.deptList
var dept: Dept = Dept(deptName: "", rates: [])
var body: some View {
List {
ForEach(depts, id: \.deptName) { dept in // <-- here
NavigationLink(destination: RateCardView(dept: dept)) {
Label(dept.deptName, systemImage: "person") // <-- here
}
}
}
}
}
struct Dept: Identifiable {
let id: UUID
var deptName: String
var rates: [HourlyRates]
init(id: UUID = UUID(), deptName: String, rates: [HourlyRates]) {
self.id = id
self.deptName = deptName
self.rates = rates
}
}
extension Dept {
// here for testing
static let deptList: [Dept] = [
Dept(deptName: "Development", rates: [
HourlyRates(year: 1, shiftWorkerRate: 0, managerRate: 20),
HourlyRates(year: 2, shiftWorkerRate: 0, managerRate: 21),
HourlyRates(year: 3, shiftWorkerRate: 0, managerRate: 22),
HourlyRates(year: 4, shiftWorkerRate: 0, managerRate: 23),
HourlyRates(year: 5, shiftWorkerRate: 0, managerRate: 24),
HourlyRates(year: 6, shiftWorkerRate: 0, managerRate: 25),
HourlyRates(year: 7, shiftWorkerRate: 0, managerRate: 26)]),
Dept(deptName: "Training", rates: [
HourlyRates(year: 1, shiftWorkerRate: 1, managerRate: 22),
HourlyRates(year: 2, shiftWorkerRate: 1, managerRate: 23),
HourlyRates(year: 3, shiftWorkerRate: 1, managerRate: 24),
HourlyRates(year: 4, shiftWorkerRate: 1, managerRate: 25),
HourlyRates(year: 5, shiftWorkerRate: 1, managerRate: 26),
HourlyRates(year: 6, shiftWorkerRate: 1, managerRate: 27),
HourlyRates(year: 7, shiftWorkerRate: 1, managerRate: 28)]),
Dept(deptName: "Marketing", rates: [
HourlyRates(year: 1, shiftWorkerRate: 2, managerRate: 22),
HourlyRates(year: 2, shiftWorkerRate: 2, managerRate: 23),
HourlyRates(year: 3, shiftWorkerRate: 2, managerRate: 24),
HourlyRates(year: 4, shiftWorkerRate: 2, managerRate: 25),
HourlyRates(year: 5, shiftWorkerRate: 2, managerRate: 26),
HourlyRates(year: 6, shiftWorkerRate: 2, managerRate: 27),
HourlyRates(year: 7, shiftWorkerRate: 2, managerRate: 28)])
]
}
struct HourlyRates: Identifiable {
let id: UUID
var year: Int
var shiftWorkerRate: Double
var managerRate: Double
init(id: UUID = UUID(), year: Int, shiftWorkerRate: Double, managerRate: Double) {
self.id = id
self.year = year
self.shiftWorkerRate = shiftWorkerRate
self.managerRate = managerRate
}
}

Reading selection from picker SwiftUI

I'm creating a picker in which a food product is selected from the array productList of type Product and I'm trying to create text boxes that output every variable stored in whichever product was selected. However, although the code is successfully built, the picker won't allow the user to make a selection. How can I fix this?
This is my code:
struct AddView : View {
#State var selectFood = 0
#ObservedObject var database : Database
var body: some View {
VStack{
Picker(selection: $selectFood, label: Text("What did you eat?")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white))
{
ForEach(database.productList) { (productList: Product) in
Text(productList.name)
}
}
.pickerStyle(MenuPickerStyle())
Spacer(minLength: 100)
ZStack {
Rectangle()
.frame(width: 350, height: 90, alignment: .center)
.foregroundColor(.white)
.opacity(0.25)
.offset(y: 40)
.cornerRadius(10)
Text("Calories: \(database.productList[selectFood].calories)")
}
Spacer()
Text("Enter")
Spacer()
}
.padding(.horizontal, 50)
}
}
This is the code where the array is stored:
struct Product : Identifiable {
var id = UUID()
var name : String
var calories : Double
var protein : Double
var carbs : Double
var fats : Double
var weight : Double
}
class Database : ObservableObject{
#Published var productList = [Product]()
init() {
self.productList = [
Product(name: "Apple", calories: 52, protein: 0.3, carbs: 14, fats: 0.2, weight: 80),
Product(name: "Avocado", calories: 160, protein: 2, carbs: 9, fats: 15, weight: 600),
Product(name: "Banana", calories: 89, protein: 1.1, carbs: 23, fats: 0.3, weight: 120),
Product(name: "Broccoli", calories: 34, protein: 2.8, carbs: 5, fats: 0.4, weight: 225),
Product(name: "Burger", calories: 264, protein: 13, carbs: 30, fats: 10, weight: 110),
Product(name: "Carrot", calories: 41, protein: 0.9, carbs: 10, fats: 0.2, weight: 61),
Product(name: "Cheerios", calories: 379, protein: 6, carbs: 83, fats: 5, weight: 40),
Product(name: "Cherry", calories: 50, protein: 1, carbs: 12, fats: 0.3, weight: 5),
Product(name: "Chicken Nuggets", calories: 302, protein: 16, carbs: 15, fats: 20, weight: 16),
Product(name: "Cocoa Pops", calories: 389, protein: 5, carbs: 85, fats: 2.9, weight: 45),
Product(name: "Corn Flakes", calories: 357, protein: 8, carbs: 84, fats: 0.4, weight: 45),
Product(name: "Crunchy Nuts", calories: 402, protein: 6, carbs: 82, fats: 5, weight: 45),
Product(name: "Eggs", calories: 196, protein: 14, carbs: 0.8, fats: 15, weight: 60),
Product(name: "Fries", calories: 312, protein: 3.4, carbs: 43, fats: 15, weight: 100),
Product(name: "Froasted Flakes", calories: 369, protein: 4, carbs: 89, fats: 1.7, weight: 45),
]
}
}
Type of selection should be same as type of Picker data block id or tag, so if you want selected index, then it should be like
struct AddView : View {
#State var selectFood = 0
#ObservedObject var database : Database
var body: some View {
VStack{
Picker(selection: $selectFood, label: Text("What did you eat?")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white))
{
ForEach(database.productList.indices, id: \.self) { i in // << here
Text(database.productList[i].name) // << and here
}
}
.pickerStyle(MenuPickerStyle())
// ... other code

SwiftUI Array List

I've created a list of food products with stored data such as calories, protein, category, etc. I've made an array of categories in order to categorize these products into groups and I'm now trying to reference this array when stating the data in each product, but when doing this (Apple variable in line 16) I get the error:
"Cannot use instance member 'categories' within property initializer; property initializers run before 'self' is available"
This is my code:
struct Product : Identifiable {
var id = UUID()
var productName : String
var calories : Double
var protein : Double
var carbs : Double
var fats : Double
var weight : Double
var category : String
}
struct Data {
#State var categories = ["Animal Products", "Dairy", "Fast Food", "Fruits", "Grains", "Nuts", "Vegetables", "Wheat"]
var Apple = Product(productName: "Apple", calories: 52, protein: 0.3, carbs: 14, fats: 0.2, weight: 80, category: categories[3])
var Avocado = Product(productName: "Avocado", calories: 160, protein: 2, carbs: 9, fats: 15, weight: 600, category: <#T##String#>)
var Banana = Product(productName: "Banana", calories: 89, protein: 1.1, carbs: 23, fats: 0.3, weight: 120, category: <#T##String#>)
var Broccoli = Product(productName: "Broccoli", calories: 34, protein: 2.8, carbs: 5, fats: 0.4, weight: 225, category: <#T##String#>)
var Burger = Product(productName: "Burger", calories: 264, protein: 13, carbs: 30, fats: 10, weight: 110, category: <#T##String#>)
var Carrot = Product(productName: "Carrot", calories: 41, protein: 0.9, carbs: 10, fats: 0.2, weight: 61, category: <#T##String#>)
var Cheerios = Product(productName: "Cheerios", calories: 379, protein: 6, carbs: 83, fats: 5, weight: 40, category: <#T##String#>)
var Cherry = Product(productName: "Cherry", calories: 50, protein: 1, carbs: 12, fats: 0.3, weight: 5, category: <#T##String#>)
}
How can I include this array inside of the Product list?
It looks like categories are predefined, then here is a solution for your case - make categories static constant:
struct Data {
static let categories = ["Animal Products", "Dairy", "Fast Food", "Fruits", "Grains", "Nuts", "Vegetables", "Wheat"]
var Apple = Product(productName: "Apple", calories: 52, protein: 0.3,
carbs: 14, fats: 0.2, weight: 80, category: categories[3])
// ... others
}

Access a value in a 2D array through programming in Swift

I create Aliment struct.
And i have an array of Aliment.
struct Aliment {
let name: String
let vitamineARetinol: Float
let vitaminC: Float
let vitaminD: Float
let calories: Float
let grammage: Float
}
let ListAlimentsBrut = [
Aliment(name: "Orange", vitamineARetinol: 0.5, vitaminC: 57, vitaminD: 0.98, calories: 140, grammage: 100),
Aliment(name: "Pomme", vitamineARetinol: 0.2, vitaminC: 6.25, vitaminD: 0.38, calories: 120, grammage: 100),
Aliment(name: "Poire", vitamineARetinol: 0.1, vitaminC: 4.62, vitaminD: 0.58, calories: 140, grammage: 100),
Aliment(name: "Laitue", vitamineARetinol: 0.3, vitaminC: 4.72, vitaminD: 0.92, calories: 105, grammage: 100),
Aliment(name: "Laitue", vitamineARetinol: 0.7, vitaminC: 4.72, vitaminD: 0.63, calories: 122, grammage: 100),
Aliment(name: "Poivron Jaune", vitamineARetinol: 0, vitaminC: 184, vitaminD: 0, calories: 29.2, grammage: 100)
]
how can i access the calorie value of the second food, i mean 120 calories for "Pomme", but through programming and not directly.
Thank you.
You can access the second element of the an array using the subscript method (arrayProperty[index]), note that the first element has an index of 0, in your case :
ListAlimentsBrut[1].calories
Also, I would recommend to follow the naming convention in swift meaning that the property ListAlimentsBrut should start with a lower case and to name the property without saying the type of the data (here list)and keeping consistency between language (just english, not a mix of french and english) like that for exemple :
let rawIngredients = [...]

Swift: Addition between value when duplicate strings in an array

Let's say I have an array that looks like this:
let games = [
Game(type: "Soccer", value: 1),
Game(type: "Basket", value: 3),
Game(type: "Hockey", value: 5),
Game(type: "Soccer", value: 2),
Game(type: "Soccer", value: 4),
Game(type: "Basket", value: 2)
]
I want a new array with 1 row per type with the values added to each other with matching type. Something like this:
let newGames = [
NewGame(type: "Soccer", value: 7),
NewGame(type: "Basket", value: 5),
NewGame(type: "Hockey", value: 5)
]
Help please. My brain is not cooperating.
struct Game {
let type: String
let value: Int
}
let games: [Game] = [
Game(type: "Soccer", value: 1),
Game(type: "Basket", value: 3),
Game(type: "Hockey", value: 5),
Game(type: "Soccer", value: 2),
Game(type: "Soccer", value: 4),
Game(type: "Basket", value: 2)
]
var totalValueForGame = [String: Int]()
for game in games {
totalValueForGame[game.type] = game.value + (totalValueForGame[game.type] ?? 0)
}
let newGames = totalValueForGame.map { Game(type: $0, value: $1) }
print(newGames)
Output:
[Game(type: "Soccer", value: 7), Game(type: "Hockey", value: 5), Game(type: "Basket", value: 5)]
class Game {
var type: String
var value: Int
init(type: String, value: Int) {
self.type = type
self.value = value
}
}
let games: [Game] = [
Game(type: "Soccer", value: 1),
Game(type: "Basket", value: 3),
Game(type: "Hockey", value: 5),
Game(type: "Soccer", value: 2),
Game(type: "Soccer", value: 4),
Game(type: "Basket", value: 2)
]
var gameTotals:[Game] = []
for key in Set(games.map{$0.type}) {
gameTotals.append(Game(type: key, value: games.filter{$0.type == key}.reduce(0){$0+$1.value}))
}
gameTotals // [{type "Soccer", value 7}, {type "Hockey", value 5}, {type "Basket", value 5}]
My (ugly) solution :D :D
import Cocoa
class Game {
var name:String
var value:Int
init(withName aName:String, andValue value:Int) {
self.name = aName
self.value = value
}
}
var someSports:[Game] = []
var tempDictOfGames:[String:Int] = [:]
var sports:[String] = ["Soccer", "Volleyball", "Tennis", "Rugby", "Tennis", "Soccer", "Tennis", "Cricket"]
var values:[Int] = [1, 5, 3, 8, 2, 9, 4, 7]
for (var i = 0; i < sports.count; i++) {
var availableGameValue:Int? = tempDictOfGames[sports[i]]
if let myValue = availableGameValue {
tempDictOfGames[sports[i]]! += values[i]
} else {
tempDictOfGames[sports[i]] = values[i]
}
}
for (k, v) in tempDictOfGames {
let newGame = Game(withName: k, andValue: v)
someSports.append(newGame)
}

Resources