首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将列表中的对象按两个字段分组?

如何将列表中的对象按两个字段分组?
EN

Stack Overflow用户
提问于 2022-11-25 16:37:40
回答 1查看 34关注 0票数 0

我想根据对象中的两个字段对对象列表进行分组。

假设我有这样一个物体:

代码语言:javascript
运行
复制
data class ItemDataDTO(
    val itemId: BigInteger?,
    val sequence: BigInteger?,
    val serialNumber: String?,
    val pickingId: String?,
    val runId: String? = null,
    val warehouse: String?,
)

现在,我有了一个包含许多项的ItemDataDTO列表。我想按runIdpickingId对它们进行分组(因为我需要那些具有相同的pickingIdrunId的项目)。

代码语言:javascript
运行
复制
val items: List<ItemDataDTO> = someItemRepository.getItemsForWarehouse("someWarehouseId")
val groupedItems = items.groupBy({ it.runId }, { it.pickingId })

这不管用。我发现我可以使用groupingBy()函数和一个Triple,但我只想将它们按两个值分组.

代码语言:javascript
运行
复制
val groupedItems = items.groupingBy { Triple(it.runId, it.pickingId, null) }

但这也不起作用。我尝试添加第三个参数,而不是null,使用it.warehouse

代码语言:javascript
运行
复制
val groupedItems = items.groupingBy { Triple(it.runId, it.pickingId, it.warehouse) }

它返回Grouping<ItemDataDTO, Triple<String?, String?, String?>>的一个实例,我不知道如何处理这个对象。

我能做些什么来正确地分组这些对象呢?

在一个完美的世界里,我想把这个列表转换成这样的列表:

代码语言:javascript
运行
复制
data class PickingList(
    val runId: String,
    val pickingId: String,
    val items: List<ItemDataDTO>,
)

所以输出将是一个List<PickingList>

EN

回答 1

Stack Overflow用户

发布于 2022-11-25 18:26:14

它没有什么特别之处!groupBy接受一个keySelector函数,该函数返回一些值作为该项的键。因此,如果要匹配两个属性,则该关键项需要由这两个值组成。

包含两个项的Triple是一个Pair,所以您可以这样做:

代码语言:javascript
运行
复制
// just FYI, "it.runId to it.pickingId" is shorthand for a Pair - you see it more
// when defining key/value pairs for maps though. "Pair(x, y)" might read better here
// since you're really just combining values, not describing how one relates to the other
items.groupBy { Pair(it.runId, it.pickingId) }

因此,每一项都将生成一个具有这两个值的Pair。与Pair匹配的任何其他项(就equals函数而言)都将放在同一个组中。这有点像添加到一个Map,只是如果一个键已经存在,这个值就会添加到一个列表中,而不是覆盖之前的值。

你真的可以用任何钥匙做到这一点。PairTriple只是打包几个项目的快速、通用的方便类--但是很多时候最好定义自己的数据结构,例如使用data class。只要具有相同数据的两个实例相等,它们就被计算为分组的相同键。

至于你想要的输出,用PickingList.您可以在分组操作中使用类似的东西--但在这种情况下,您必须自己重新实现groupBy。您必须获取一个项,并从要考虑的属性中计算出它的复合键。然后,您需要在为组创建的某个商店中找到该密钥的匹配项。

如果是PickingList的列表,则需要遍历每个If,将其if与所需的if进行比较,如果找到匹配,则将其添加到列表中,如果找不到则创建对象。

如果您存储的是Pair(id1, id2) -> PickingList映射,那么在生成查找键方面,这与groupBy的工作方式非常接近。在这种情况下,您可能只想使用groupBy对所有项进行分组,然后转换最终的映射:

代码语言:javascript
运行
复制
items.groupBy { Pair(it.runId, it.pickingId) }
    .map { (ids, list) ->
        PairingList(runId = ids.first, pickingId = ids.second, items = list)
    }

这将获取每个映射条目(ID的Pair和按这些ID分组的所有事物的列表),并使用它从键/值数据创建PairingList。基本上,一旦对所有数据进行了分组,就可以将其转换为要使用的数据结构。

这也是一个很好的例子,说明为什么您自己的数据类可能比仅仅使用Pair更好-- it.first并没有真正告诉您这个值在Pair中是什么,只是它是两个值中的第一个。鉴于

代码语言:javascript
运行
复制
data class IdCombo(val runId: String, val pickingId: String)

它的工作原理与Pair相同,但这些属性具有有用的名称,使您的代码更加可读性更强,更不容易出现bug:

代码语言:javascript
运行
复制
map { (ids, list) ->
        // didn't even bother with the named arguments, since the names are in
        // the ids object now!
        PairingList(ids.runId, ids.pickingId, items = list)
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74575684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档