Home > Software design >  Swift || How to filter kid array by parent array elements?
Swift || How to filter kid array by parent array elements?

Time:04-11

i have two data models as below:


class Card {
    let type: String
    let name: String
    let icon: String
    
    init(
        type: String,
        name: String,
        icon: String
    ) {
        self.type = type
        self.icon = icon
        self.name = name
    }
}

class Product {
    let type: String? // please watch out here is optional value
    let imageUrl: String
    let content: String
    
    init(
        type: String?,
        imageUrl: String,
        content: String
    ) {
        self.type = type
        self.imageUrl = imageUrl
        self.content = content
    }
}

And I managed to get the above two entities mapped data with API response, right now I got a new requirement that needs to merge the above two data entities as the following structure. and products be filtered by same type which included in both Card and Product

class MergedData {
    let type: String // same "type" with "Product.type"
    let name: String
    let icon: String
    let products: [Product] // products inserted here should have same "type" 
   
    init(
        type: String,
        name: String,
        icon: String,
        products: [Product]
    ) {
        self.type = type
        self.icon = icon
        self.name = name
        self.products = products
    }
    
}

lets say we have a DemoViewModel here

class DemoViewModel {
    
    var cards: [Card]
    var products: [Product]
    var mergedData: [MergedData] = [] 
    
    init(cards: [Card],
         products: [Product]) {
        self.cards = cards  
        self.products = products
    }
    
    func getMergedData() -> [MergedData] {
        // how to write here ?
    }
}

how to write the content of getMergedData ?

CodePudding user response:

I would first group the products array on type and use that for looking up the products for a card

This first solution will only merge data for cards that has matching products

func merge(cards: [Card], with products: [Product]) -> [MergedData] {
    let groupedProducts = Dictionary(grouping: products, by: \Product.type)

    return cards.compactMap { card in
        guard let products = groupedProducts[card.type] else { return nil }
        return MergedData(card: card, products: products)
    }
}

but if you want to create a MergedData instance for each Card instance you can replace the last part with

return cards.map { card in
    let products = groupedProducts[card.type]
    return MergedData(card: card, products: products)
}

Note that I created a custom init for this to make the code cleaner

init(card: Card, products: [Product]?) {
    type = card.type
    icon = card.icon
    name = card.name
    self.products = products ?? []
}

CodePudding user response:

Try:

func getMergedData() -> [MergedData] {
    cards.map{ card in
        MergedData(type: card.type, name: card.name, icon: card.icon, products: products.filter{product in product.type == card.type })
    }
}

this itterates through all cards creates a new MergedData for each card and assigns all Product that have the same type.

  • Related