Kotlin - 需要分组的元素列表,其中一些具有相同的 ID



我有一个清单,比如说食物菜肴。 数据类如下所示:

data class FoodItem(val categoryId: Int, val categoryTitle: String, val title: String, val text: String)

因此,假设我有这些数据:

val list = listOf(FoodItem(1, "Mexican", "Burrito", "Wrapped food"),
FoodItem(2, "Italian", "Pizza", "Dough, cheese and tomato"),
FoodItem(3, "BBQ", "Brisket", "Does it need explaining?"),
FoodItem(4, "Japanese", "Sushi", "Raw fish and rice!"),
FoodItem(2, "Italian", "Pasta", "Great with meatballs!"))

我希望将其分组到一个列表中,其中 CategoryId 和 CategoryTitle 匹配的那些被分组。

所以最后我想要一个包含 4 个项目的列表,其中意大利语类别在自己的列表中有 2 个项目。所以我想象我需要一个新的数据类,它可以保存一个包含 id 和标题的类别,然后是一个食物描述列表或包含比萨饼、意大利面等的东西,所有这些都在它所在的类别中。

我想要一个类似于这样的输出:

GroupedFoodItemViewModel(category=Category(categoryId=2, categoryTitle=Italian), foods=[FoodItemViewModel(categoryId=2, categoryTitle="Italian", foodTitle="Pasta", foodText="Great with meatballs!"), FoodItemViewModel(categoryId=2, categoryTitle=Italian, foodTitle=Pizza, foodText=Dough, cheese and tomato)])

其余的将在与此类似的列表中,仅在"食物"数组下有一个元素。我想在回收器视图中使用它,其中我将类别作为标题,并在类别下方显示食物列表。

假设存在 1:1 的对应关系,我不建议为类别 ID 和标题使用冗余属性。这是招人错误。您应该有一个恒定的 ID 映射到某处的标题,并且类可以通过这种方式拉入标题:

val CATEGORY_IDS_TO_TITLES = mapOf(1 to "Mexican", 2 to "Italian", 3 to "BBQ", 4 to "Japanese")
data class FoodItem(val categoryId: Int, val title: String, val text: String) {
val categoryTitle: String get() = CATEGORY_IDS_TO_TITLES[categoryId] ?: error("Unknown category ID")
}
data class Category(val categoryId: Int) {
val categoryTitle: String get() = CATEGORY_IDS_TO_TITLES[categoryId] ?: error("Unknown category ID")
}

然后,给定将类别与列表组合在一起的类:

data class GroupedFoodItemViewModel(val category: Category, val items: List<FoodItem>)

您可以使用原始列表上的groupBy根据类别 ID 收集单独的列表,然后将生成的Map<Int, List<FoodItem>>的条目映射到 GroupedFoodItemView Model 列表中:

val grouped = list.groupBy(FoodItem::categoryId)
.entries.map { (id, itemList) ->
GroupedFoodItemViewModel(Category(id), itemList)
}

我想出了一个解决方案。你特别说你想匹配你的CategoryIdCategoryTitle所以这正是我所做的:

val groupedMap = list.groupBy{ Pair(it.categoryTitle, it.categoryId) }
groupedMap.entries.first().key.first //for the name e.g. "Italian"

所以基本上 Kotlin 在其stdlib中提供了一个名为groupBy的函数,您可以在其中按给定键similarly to SQL对列表进行分组。在您的情况下,键由两个属性(CategoryIdCategoryTitle)组成。要将两者用作密钥,您可以创建一个包含这些 props 的自定义类,也可以像我一样使用Pair.代码的第二行访问结果列表的第一个条目 - 然后访问它的键(例如Pair("Italian", 2)),最后使用first访问Pair的第一个属性(在这种情况下为CategoryTitle)。

由于您的 CategoryId 似乎与您的 CategoryTitle 相关,因此您可能只能按 CategoryTitle 进行分组。这将看起来像这样:

val groupedMap = list.groupBy{ it.categoryTitle }

然后名称(例如意大利语)将是生成的 groupedMap 的键。


更改要求后编辑

所以基本上你可以这样做:

val result = list.groupBy{ foodItem ->
Category(foodItem.categoryId, foodItem.categoryTitle)
}
result.forEach { entry ->
entry.value.map { foodItem ->
with(foodItem) {
FoodItemViewModel(
categoryId,
categoryTitle,
title,
text
)
}
}
}
data class FoodItem(val categoryId: Int, val categoryTitle: String, val title: String, val text: String)
data class FoodItemViewModel(val categoryId: Int, val categoryTitle: String, val foodTitle: String, val foodText: String)
data class Category(val categoryId: Int, val categoryTitle: String) 

我在这里所做的只是在对元素进行分组的同时创建Category(键)。然后我只需要将结果值从FoodItem映射到FoodItemViewModel

您可能需要考虑稍微重构一下类。Category的属性也存在于FoodItemFoodItemViewModel中。

希望这能:)解决您的问题。

你可以通过groupBy来做到这一点。

请检查以下代码:

data class FoodItem(val categoryId: Int, val categoryTitle: String, val title: String, val text: String)
val list = listOf(FoodItem(1, "Mexican", "Burrito", "Wrapped food"),
FoodItem(2, "Italian", "Pizza", "Dough, cheese and tomato"),
FoodItem(3, "BBQ", "Brisket", "Does it need explaining?"),
FoodItem(4, "Japanese", "Sushi", "Raw fish and rice!"),
FoodItem(1, "Italian", "Sushi", "Raw fish and rice!"),
FoodItem(2, "Italian", "Pasta", "Great with meatballs!"))
val groupMap = list.groupBy{ Pair(it.categoryId , it.categoryTitle)   }
println(groupMap)

输出:

{(1, Mexican)=[FoodItem(categoryId=1, categoryTitle=Mexican, title=Burrito, text=Wrapped food)], 
(2, Italian)=[FoodItem(categoryId=2, categoryTitle=Italian, title=Pizza, text=Dough, cheese and tomato),
FoodItem(categoryId=2, categoryTitle=Italian, title=Pasta, text=Great with meatballs!)], 
(3, BBQ)=[FoodItem(categoryId=3, categoryTitle=BBQ, title=Brisket, text=Does it need explaining?)], 
(4, Japanese)=[FoodItem(categoryId=4, categoryTitle=Japanese, title=Sushi, text=Raw fish and rice!)], 
(1, Italian)=[FoodItem(categoryId=1, categoryTitle=Italian, title=Sushi, text=Raw fish and rice!)]}

最新更新