简体   繁体   中英

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

在此处输入图像描述

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.

在此处输入图像描述

If I added the next condition, it returns nil

在此处输入图像描述

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.

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]

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM