Searching for the position of an item in an array within an array?

I have an array of products and a separate dictionary of inventory. I want to be able to use the keys of the dictionary to "look up" the colorName within the product catalog using the name of the item found in the dictionary. I know you can search for item position within an array, but how to you do this if it is an array within an array?



The products:
Code Block
Product(brand: "Academia", category: "Bandages", colorName: [ "Blue", "Green", "Purple", "Red" ], item: ["academiaBandagesBlue", "academiaBandagesGreen", "academiaBandagesPurple", "academiaBandagesRed"])

The inventory
Code Block
var tackInventory: [ String : Int] = [
   "academiaBandagesBlue" : 1,
    "academiaBandagesGreen" : 0,
    "academiaBandagesPurple" : 0,
    "academiaBandagesRed" : 0


Answered by Claude31 in 658659022
You could do something like this:

Code Block
struct Product {
var brand: String
var option: [String]
var item: [String]
}
let products = [
Product(brand: "Academia", option: ["Blue", "Red"], item: ["academiaBandagesBlue", "academiaBandagesRed"]),
Product(brand: "Academia", option: ["Purple", "Green"], item: ["academiaBandagesPurple", "academiaBandagesGreen"])
]
var tackInventory: [ String : Int] = [
"academiaBandagesBlue" : 1,
"academiaBandagesGreen" : 0,
"academiaBandagesPurple" : 0,
"academiaBandagesRed" : 0
]
let filteredKeys = tackInventory.filter { $0.value > 0}.map {$0.key} // Select the keys to search for
print(filteredKeys)
for key in filteredKeys {
let filteredProducts = products.filter { $0.item.contains(key)} // all the products that contain that specific item
for product in filteredProducts {
if let itemPosition = product.item.firstIndex(of: key) { // What is the position of key in item list (there should be only one ?
let foundColor = product.option[itemPosition] // If color are in the same order than item, then we got it
print("key", key, "color", foundColor)
}
}
}

and get:
["academiaBandagesBlue"]
key academiaBandagesBlue color Blue


But your coding of Product is not robust at all.
If you do not put color and item in same order, you get wrong result.

You'd better have a dictionary linking item with its color.

You could also define item as a couple of String:
Code Block
struct Product {
var brand: String
var item: [(color: String, ref: String)]
}
let products = [
Product(brand: "Academia", item: [("Blue", "academiaBandagesBlue"), ("Red", "academiaBandagesRed")]),
Product(brand: "Academia", item: [("Purple", "academiaBandagesPurple"), ("Green", "academiaBandagesGreen")])
]
var tackInventory: [ String : Int] = [
"academiaBandagesBlue" : 1,
"academiaBandagesGreen" : 0,
"academiaBandagesPurple" : 0,
"academiaBandagesRed" : 0
]
let filteredKeys = tackInventory.filter { $0.value > 0}.map {$0.key} // Select the keys to search for
for key in filteredKeys {
let filteredProducts = products.filter { product in
for item in product.item { if item.ref == key { return true }}
return false
} //all the products that contain that specific item
for product in filteredProducts {
for item in product.item where item.ref == key {
let foundColor = item.color
print("key", key, "ref", item.ref, "color", foundColor)
}
}
}

and get
key academiaBandagesBlue ref academiaBandagesBlue color Blue
You should give an example ot the array and what you want to find position of, that would be easier to understand.
Is it the one you had in other post ?
Code Block
let products = [
Product(brand: "Academia", option: ["Blue", "Red"], item: ["academiaBandagesBlue", "academiaBandagesRed"]),
Product(brand: "Academia", option: ["Purple", "Green"], item: ["academiaBandagesPurple", "academiaBandagesGreen"])
]


 I want to be able to use the keys of the dictionary to "look up" the colorName within the product catalog using the name of the item found in the dictionary.

Please confirm the following:
  • you use the key in inventory, such as "academiaBandagesBlue" ?

        Which key do you select ? The one with non null value ?
  • You look for products that contain the item ?

  • Then you get the color ?


I don't understand what the products are?
Code Block
Product(brand: "Academia", category: "Bandages", colorName: [ "Blue", "Green", "Purple", "Red" ], item: ["academiaBandagesBlue", "academiaBandagesGreen", "academiaBandagesPurple", "academiaBandagesRed"])

Is it the only product ?
It has all items and all colors. How will you match color and item ?
Accepted Answer
You could do something like this:

Code Block
struct Product {
var brand: String
var option: [String]
var item: [String]
}
let products = [
Product(brand: "Academia", option: ["Blue", "Red"], item: ["academiaBandagesBlue", "academiaBandagesRed"]),
Product(brand: "Academia", option: ["Purple", "Green"], item: ["academiaBandagesPurple", "academiaBandagesGreen"])
]
var tackInventory: [ String : Int] = [
"academiaBandagesBlue" : 1,
"academiaBandagesGreen" : 0,
"academiaBandagesPurple" : 0,
"academiaBandagesRed" : 0
]
let filteredKeys = tackInventory.filter { $0.value > 0}.map {$0.key} // Select the keys to search for
print(filteredKeys)
for key in filteredKeys {
let filteredProducts = products.filter { $0.item.contains(key)} // all the products that contain that specific item
for product in filteredProducts {
if let itemPosition = product.item.firstIndex(of: key) { // What is the position of key in item list (there should be only one ?
let foundColor = product.option[itemPosition] // If color are in the same order than item, then we got it
print("key", key, "color", foundColor)
}
}
}

and get:
["academiaBandagesBlue"]
key academiaBandagesBlue color Blue


But your coding of Product is not robust at all.
If you do not put color and item in same order, you get wrong result.

You'd better have a dictionary linking item with its color.

You could also define item as a couple of String:
Code Block
struct Product {
var brand: String
var item: [(color: String, ref: String)]
}
let products = [
Product(brand: "Academia", item: [("Blue", "academiaBandagesBlue"), ("Red", "academiaBandagesRed")]),
Product(brand: "Academia", item: [("Purple", "academiaBandagesPurple"), ("Green", "academiaBandagesGreen")])
]
var tackInventory: [ String : Int] = [
"academiaBandagesBlue" : 1,
"academiaBandagesGreen" : 0,
"academiaBandagesPurple" : 0,
"academiaBandagesRed" : 0
]
let filteredKeys = tackInventory.filter { $0.value > 0}.map {$0.key} // Select the keys to search for
for key in filteredKeys {
let filteredProducts = products.filter { product in
for item in product.item { if item.ref == key { return true }}
return false
} //all the products that contain that specific item
for product in filteredProducts {
for item in product.item where item.ref == key {
let foundColor = item.color
print("key", key, "ref", item.ref, "color", foundColor)
}
}
}

and get
key academiaBandagesBlue ref academiaBandagesBlue color Blue
Thanks, testing it out now. the product below shows four different items:

Code Block
Product(brand: "Academia", category: "Bandages", colorName: [ "Blue", "Green", "Purple", "Red" ], item: ["academiaBandagesBlue", "academiaBandagesGreen", "academiaBandagesPurple", "academiaBandagesRed"])

So the following identifies which item of the selected product the view will show
Code Block if let itemPosition = product.item.firstIndex(of: key) {
       // What is the position of key in item list (there should be only one ?


//If color are in the same order than item, then we got it
The colors are in the same order of the items


I am trying to use the inventory to populate a stackView of buttons, showing the amount of each item. However, I might have some error as it is showing up different items each time. Is this because dictionaries don't show things in a specific order? Maybe I should change the tackInventory into an array also...

Code Block
struct Tack {
var item: String
var amount: Int
}
var tackInventory = [
Tack(item: "academiaBandagesBlue", amount: 2)
Tack(item: "academiaBandagesRed", amount: 5)
]






Yes, dictionaries have no fixed order.
And arrays keep the order.

I don't understand why the order of tackInventory should change anything. How you use tackInventory.
I don't understand either why it would show different items ; different order of same items should be logical.

Could you show the complete code you have now ?
And explain what you get exactly.
It was working in the playground but not the app. As I thought I had used the code incorrectly :). With some work I got it to function in the app too. Here is how it looks now:

Code Block     for (key,value) in tackInventory{
        let button = UIButton()
        button.addTarget(self, action: #selector(self.selectTack(sender:)), for: .touchUpInside)
            let filteredProducts = products.filter { $0.item.contains(key)}
            for product in filteredProducts {
                if let itemPosition = product.item.firstIndex(of: key) {
                    let foundColor = product.colorName[itemPosition]
                    if value > 0 {
                    button.setTitle("\(foundColor) \(product.brand) \(product.category), amount: \(value)", for: UIControl.State.normal)
                    tackStack.addArrangedSubview(button)
                }
            }
        }
    }


Searching for the position of an item in an array within an array?
 
 
Q