Search code examples
androidperformancekotlindatamapper

Kotlin: How to map lists with nested lists


I want to convert Network DTOs (rest api response) to Dabatabase DTOs in Kotlin. The Network DTO contains a List as field and the items in that list also contain lists of other data. Below is the representation of network response or Network DTO

{
   categories: [
      {
         catId: 0,
         name: "Category A",
         products: [
             {
                 prodId: 900,
                 name: "Product 1"
                 ingredients: [
                     {
                         name: "Ingre 1"
                     }
                 ]
             }
         ]
      }
   ]
}

I want to extract and convert the list of all categories, then list of all products and then list of all ingredients into three separate lists and also want to convert these data into their respective Database DTOs.

I have created a piece of code that is doing the required task but i am sure that there are performance issues and there must be some more kotlinish solution.

val dbCategories = networkCategories?.map {
                    DBCategory(
                            catId = it.catId,
                            name = it.name
                    )
                }

val dbProducts = networkCategories?.map { it.networkProducts }?.map {
                it.map { singleNetworkProduct ->
                    DBProduct(
                            prodId = singleNetworkProduct.prodId,
                            name = singleNetworkProduct.name,
                    )
                }
            }?.flatten() // flatten to remove the nested array lists created by repeated map functions

In above code i am skipping the extraction of ingredients array for the sack of simplicity.


Solution

  • Use FlatMap.

    val dbProducts = networkCategories.flatMap { it. networkProducts }
        .map { DBProduct( ... ) }
    
    val dbIngredients = networkCategories.flatMap { it. networkProducts }
        .flatMap { it.networkIngredients }.map { DBIngredient( ... ) }
    

    If you are concerned about performance issues because the network list is iterated more than once, and want to iterate the original network lists only one time, then you can use normal for loop or forEach, and add the items yourself in three mutable lists.

    Or, you can use mapTo:

    val dbProducts = mutableListOf<DBProduct>()
    val dbIngredients = mutableListOf<DBIngredient>()
    
    val dbCategories = networkCategories.map {
    
        it.products.mapTo(dbProducts) {
    
            it.ingredients.mapTo(dbIngredients) {
                DBIngredient( ... )
            }
    
            DBProduct( ... )
        }
    
        DBCategory( ... )
    }