Home > OS >  How to filter a nested array of dictionaries with multiple conditions from another array in Swift
How to filter a nested array of dictionaries with multiple conditions from another array in Swift

Time:01-03

enter image description here

sample json data is this:

{
  "variations": [
    {
      "variation_id": 391,
      "name": "Fruit Shake - Chocolate, S",
      "price": 10,
      "attribute": [
        {
          "attribute_key": "pa_flavor",
          "name": "Flavor",
          "option": "Chocolate"
        },
        {
          "attribute_key": "pa_size",
          "name": "Size",
          "option": "S"
        }
      ]
    },
    {
      "variation_id": 385,
      "name": "Fruit Shake - Banana, L",
      "price": 18,
      "attribute": [
        {
          "attribute_key": "pa_flavor",
          "name": "Flavor",
          "option": "Banana"
        },
        {
          "attribute_key": "pa_size",
          "name": "Size",
          "option": "L"
        }
      ]
    },
    {
      "variation_id": 386,
      "name": "Fruit Shake - Banana, M",
      "price": 15,
      "attribute": [
        {
          "attribute_key": "pa_flavor",
          "name": "Flavor",
          "option": "Banana"
        },
        {
          "attribute_key": "pa_size",
          "name": "Size",
          "option": "M"
        }
      ]
    }
  ]
}

my problem is, getting the variation_id where 2 or more attributes matches the array of string.

for example, chosenProduct = ["Banana", "L"]

I tried filter and contains but theres no way to match the other item from chosenProduct.

enter image description here

If I added the next condition, it returns nil

enter image description here

CodePudding user response:

You can try this:

let varID = product.variations?.filter { att in
            var matchedAttributes = 0
            for thisAttribute in att.attribute {
                if chosenProduct.contains(where: {$0 == thisAttribute.option}) {
                    matchedAttributes  = 1
                }
            }
            if matchedAttributes >= 2 {
                return true
            }
            return false
  }

Let me know if there's any doubt.

CodePudding user response:

You can try this :

var chosenProduct = ["Banana","L"]
var expectedIds : [Int] = [Int]()

datas.variations?.map{ val in
    val.attribute.map({ val2 in
        let filtered = val2.enumerated().filter({chosenProduct.contains($0.element.option!)})
        
        if filtered.count == chosenProduct.count{
            expectedIds.append(val.variation_id!)
        }
        
    })
}

print(expectedIds) // [385]

I put the id's in array because of if you want to change your chosenProcudt example "Banana" (count 1 ). This mapping must be return variation_id like [385,386]

CodePudding user response:

You can a method to Variation to make things easier:

extension Variation {
    func attributesMatching(options: [String]) -> [Attribute] {
        attribute.filter { options.contains($0.option) }
    }
}

Then, you can just write:

let filtered = product.variations.filter { $0.attributesMatching(options: chosenProductOptions).count >= 2 }
print(filtered.map { $0.variationID })
  • Related