Kotlin - ArrayList 的自定义排序

Kotlin - custom sorting of ArrayList

我正在构建一个 Android 应用程序,我想在其中实现 User

的自定义排序

让我详细解释一下需求。

假设 ArrayList 类型 User 中存储了 15 个用户,每个用户都有单独的角色映射。用户必须 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
        }))
    
    }

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

你实际上走对了方向。您只需要另外按角色排序。像这样:

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<Role, List<Users>> 的东西,那么:

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

我相信Broot的回答是好的;如果您需要一个“工作示例”,我相信有 smarter/better/more 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)]