Home > OS >  Kotlin: Efficient way of sorting list using another list and alphabetical order
Kotlin: Efficient way of sorting list using another list and alphabetical order

Time:11-04

I want to sort the students list based on their popularity (this list is always sorted by their points) and then sort the ones that aren't on that list in alphabetical order

  • The two lists look like:
students = listOf<Student>(
    Student(id = 3, name ="mike"),
    Student(id = 2,name ="mathew"),
    Student(id = 1,name ="john"),
    Student(id = 4,name ="alan")
)
val popularity = listOf<Ranking>(
    Ranking(id= 2, points = 30),
    Ranking(id= 3, points = 15)
)
  • The result I'm looking for would be:
[
 Student(id=2,name"mathew"), <- first, because of popularity
 Student(id=3,name="mike"),
 Student(id=4,name="alan"), <- starting here by alphabetical order
 Student(id=1,name="john")
]

If anyone knows about an efficient way of doing this I would kindly appreciate the help

CodePudding user response:

I think you are looking for .sortedWith().

The only problem is the look-up of what is id <-> ranking. Noting that those structures very much resemble data fetched from a database so I think there is a better solution there but for what is given:

val studentRanking: List<Pair<Student, Int>> = students.map { student ->
    student to popularity.find { popularity -> student.id == popularity.id }?.points ?: 0 
}

studentRanking.sortedWith(
    Comparator<Pair<Student, Int?>> { firstStudent, secondStudent -> 
        when {
            firstStudent.second > secondStudent.second -> -1
            firstStudent.second < secondStudent.second -> 1
            else -> 0
        }    
    }.thenBy { studentPair -> studentPair.first.name }
)

Results in:

[
 Student(id=2,name"mathew"),
 Student(id=3,name="mike"),
 Student(id=4,name="alan"),
 Student(id=1,name="john")
]

CodePudding user response:

Having the rankings as a list is suboptimal, because to look things up you need to browse the list everytime, which is slow if you have many rankings. If you do have a lot of them, I would suggest to get them as a map first. You can do it easily from the list using associate.

Then you can create a custom comparator to compare by popularity and then by name:

val studentIdToPopularity = popularity.associate { it.id to it.points }

val studentComparator = compareByDescending<Student> { studentIdToPopularity[it.id] ?: 0 }.thenBy { it.name }
val sortedStudents = students.sortedWith(studentComparator)
  • Related