Kotlin - ArrayList 的自定义排序

Posted

技术标签:

【中文标题】Kotlin - ArrayList 的自定义排序【英文标题】:Kotlin - custom sorting of ArrayList 【发布时间】:2021-12-05 09:39:55 【问题描述】:

我正在构建一个 android 应用程序,我想在其中实现 User 的自定义排序

让我详细解释一下要求。

假设有 15 个用户存储在 ArrayList 类型的 User 中,每个用户都有单独的角色映射。用户必须是grouped by roles,顺序相同as below

 1.Mechanic 
 2.Plumber 
 3.Electrician

此外,在角色组内应主要根据unread message count 排序,其次根据alphabetical order 排序

案例 1:没有未读消息

基于role-based groupingalphabetical sorting(无未读消息),用户应按以下方式显示。(括号中的'0'表示未读消息数)

Aarav,Mechanic(0)
Dhruv,Mechanic(0)
Jason,Mechanic(0)
Pranav,Mechanic(0)
Zeplin,Mechanic(0)

Amit,Plumber(0)
Baskaran,Plumber(0)
Garry,Plumber(0)
Rakesh,Plumber(0)
Shekar,Plumber(0)

Balu,Electrician(0)
Ragunathan,Electrician(0)
Prem kumar,Electrician(0)
Saravanan,Electrician(0)
Thanigaivel,Electrician(0)

案例 2:未读消息计数

当有用户(在角色内)有未读聊天计数时,列表应优先考虑他们在列表中的优先级,字母顺序应视为次要。它通常应该如下所示。

Zeplin,Mechanic(20)
Pranav,Mechanic(10)
Aarav,Mechanic(0)
Dhruv,Mechanic(0)
Jason,Mechanic(0)

Garry,Plumber(5)
Rakesh,Plumber(5)
Amit,Plumber(0)
Baskaran,Plumber(0)
Shekar,Plumber(0)

Prem kumar,Electrician(10)
Balu,Electrician(0)
Ragunathan,Electrician(0)
Saravanan,Electrician(0)
Thanigaivel,Electrician(0)

请帮我完成这个。

以下是我尝试过的

 fun getListWithGroupingAndSorting()
      val users = ArrayList<User>
     // Writing logic to pull list of users from server and assigning to `users`
        return ArrayList(users.sortedWith(compareByDescending<User> 
            it.unreadMessageCount
        .thenBy 
            it.firstName
        ))
    
    

这主要根据未读消息数对列表进行排序,其次根据字母顺序但无法以上述方式完成。

【问题讨论】:

您可能必须先使用groupBy 来对它们进行分组。 @MartinMarconcini 如何完成?请帮帮我。首先它应该显示是否有机械师,然后是电工,然后是管道工。 【参考方案1】:

你实际上走的是正确的方向。您只需要另外按角色排序。像这样的:

val rolesOrder = mapOf("Mechanic" to 1, "Plumber" to 2, "Electrician" to 3)

users.sortedWith(
    compareBy<User>  rolesOrder[it.role] 
        .thenByDescending  it.unreadMessageCount 
        .thenBy  it.firstName 
)

如果你真的需要对项目进行分组而不是仅仅对它们进行排序,那么你需要像Map&lt;Role, List&lt;Users&gt;&gt; 这样的东西,那么:

users.groupByTo(sortedMapOf(compareBy  rolesOrder[it] ))  it.role 
    .mapValues  (_, value) ->
        value.sortedWith(
            compareByDescending<User>  it.unreadMessageCount 
                .thenBy  it.firstName 
        )
    

如果你有一个有序的角色列表并且你需要为它们分配索引,你可以这样做:

val rolesOrder = listOf("Mechanic", "Plumber", "Electrician")
    .withIndex()
    .associate  it.value to it.index 

请注意,如果rolesOrder 中缺少角色,则会将用户放在开头。如果这是一种可能的情况,并且您想将它们放在最后,那么像这样比较角色:

rolesOrder[it.role] ?: Integer.MAX_VALUE

【讨论】:

谢谢。当然,让我试试这个并尽快回来。 我试过了。基于字母顺序和聊天计数的排序工作正常,但分组没有发生:-(请帮帮我。 没有分组是什么意思?排序时忽略角色,所以它们在结果列表中混在一起? 是的。我刚刚试过 this.val rolesOrder = mapOf("Mechanic" to 1, "Plumber" to 2, "Electrician" to 3) users.sortedWith( compareBy rolesOrder[it.role] .thenByDescending it. unreadMessageCount .thenBy it.firstName ) 对不起,我不明白你的问题。您只需将我的代码复制并粘贴到评论中即可。我确信排序和分组的两个示例都可以正常工作,因为我在发布之前对它们进行了测试。如果它对您不起作用,那么您可能需要在问题中添加更多信息:您使用的确切代码是什么,结果是什么以及为什么它与预期不同。【参考方案2】:

我相信 Broot 的回答很好;如果您需要一个“工作示例”,我相信有更聪明/更好/更多的 kotlin 方法,但为什么不从简单开始。

在 5 分钟内,您可以想出一个运行 in the kotlin playground 的示例。

基本上:

data class User(val role: String, val unread: Int = 0)

fun main() 
    val unsorted = listOf(User("Mechanic", 5), 
                          User("Plumber", 3),
                          User("Electrician", 2),
                          User("Mechanic", 9),
                          User("Mechanic", 1),
                          User("Electrician", 8),
                          User("Mechanic", 4),
                          User("Plumber", 0))
    
    // Group them
    val sortedByRole = unsorted
        .groupBy  it.role 
        .forEach  k, group ->  
           val sortedGroup = group.sortedByDescending  user -> user.unread 
           println(sortedGroup)
         

输出:

[User(role=Mechanic, unread=9), User(role=Mechanic, unread=5), User(role=Mechanic, unread=4), User(role=Mechanic, unread=1)]
[User(role=Plumber, unread=3), User(role=Plumber, unread=0)]
[User(role=Electrician, unread=8), User(role=Electrician, unread=2)]

【讨论】:

以上是关于Kotlin - ArrayList 的自定义排序的主要内容,如果未能解决你的问题,请参考以下文章

ht-7 对arrayList中的自定义对象排序

Kotlin:null 不能是非 null 类型的值

对 Java ArrayList 的一部分进行排序

Kotlin 中的自定义数字键盘

ArrayList 的自定义 Contains 方法

使用自定义比较器时使用 TreeSet 还是 ArrayList 更好