I want to order the tasks collection by nextTime in descending order and then timePart in descending order.
the sort code works fine for the person collection, however, when it applies to tasks collection, it does not order by timePart in descending order, which is really weird. The result shows below.
2023-05-30 23:44:56.205 24842-24863/com.maxim.wordcard I/System.out: Person(name='Olivia', age=20)
2023-05-30 23:44:56.205 24842-24863/com.maxim.wordcard I/System.out: Person(name='Olivia', age=25)
2023-05-30 23:44:56.205 24842-24863/com.maxim.wordcard I/System.out: Person(name='Harry', age=10)
2023-05-30 23:44:56.205 24842-24863/com.maxim.wordcard I/System.out: Person(name='Harry', age=15)
2023-05-30 23:33:07.059 23361-23381/com.maxim.wordcard I/System.out: Task(nextTime='Wed May 31 23:23:07 GMT+08:00 2023', time=1130)
2023-05-30 23:33:07.060 23361-23381/com.maxim.wordcard I/System.out: Task(nextTime='Wed May 31 23:13:07 GMT+08:00 2023', time=1120)
2023-05-30 23:33:07.060 23361-23381/com.maxim.wordcard I/System.out: Task(nextTime='Tue May 30 23:33:07 GMT+08:00 2023', time=1140)
2023-05-30 23:33:07.060 23361-23381/com.maxim.wordcard I/System.out: Task(nextTime='Tue May 30 23:23:07 GMT+08:00 2023', time=1130).
package com.maxim.wordcard
import com.maxim.wordcard.database.entity.Task
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.util.*
@RunWith(JUnit4::class)
class CollectionSort {
@Test
fun testSortCollection() {
val calendar = Calendar.getInstance()
val task1 = Task(calendar.time, 1, 1)
task1.timePart = calendar.get(Calendar.HOUR) * 100 + calendar.get(Calendar.MINUTE) + calendar.get(Calendar.SECOND)
calendar.add(Calendar.MINUTE, -10)
val task2 = Task(calendar.time, 1, 1)
task2.timePart = calendar.get(Calendar.HOUR) * 100 + calendar.get(Calendar.MINUTE) + calendar.get(Calendar.SECOND)
calendar.add(Calendar.DATE, 1)
val task3 = Task(calendar.time, 1, 1)
task3.timePart = calendar.get(Calendar.HOUR) * 100 + calendar.get(Calendar.MINUTE) + calendar.get(Calendar.SECOND)
calendar.add(Calendar.MINUTE, -10)
val task4 = Task(calendar.time, 1, 1)
task4.timePart = calendar.get(Calendar.HOUR) * 100 + calendar.get(Calendar.MINUTE) + calendar.get(Calendar.SECOND)
val tasks = arrayListOf<Task>(task1, task2, task3, task4)
tasks.sortWith(compareByDescending<Task> { it.nextTime }.thenBy { it.timePart })
for (task in tasks) {
println(task)
}
}
@Test
fun testPerson() {
val persons = mutableListOf(
Person("Olivia", 25),
Person("Harry", 15),
Person("Olivia", 20),
Person("Harry", 10)
)
persons.sortWith(compareByDescending<Person>{ it.name }.thenBy { it.age })
for (person in persons) {
println(person)
}
}
class Person(val name: String, val age: Int, val test: String?) {
constructor(name: String, age: Int): this(name, age, "hell")
override fun toString(): String {
return "Person(name='$name', age=$age)"
}
}
}
package com.maxim.wordcard.database.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import java.sql.Time
import java.util.*
@Entity
data class Task(
@PrimaryKey(autoGenerate = true) var id: Int?,
@ColumnInfo var unknown: Int,
@ColumnInfo var search: Int,
@ColumnInfo var know: Int,
@ColumnInfo var startTime: Date,
@ColumnInfo var nextTime: Date,
/**
* [TaskStatus]
*/
@ColumnInfo var status: Int?,
@ColumnInfo var wordId: Long?,
@ColumnInfo var courseId: Long?,
@Ignore var isSkim: Boolean = false,
@Ignore var isShowDefinition: Boolean = false,
@Ignore var timePart: Int? = null,
) {
constructor(wordId: Long?, courseId: Long?) : this(null, 0, 0, 0, Date(), Date(), TaskStatus.UNSTART.status, wordId, courseId)
@Ignore
constructor(nextTime: Date, wordId: Long?, courseId: Long?) : this(null, 0, 0, 0, Date(), nextTime, TaskStatus.UNSTART.status, wordId, courseId)
/**
* Task is used as a key, its hashcode should keep the same, hence, exclude some fields which
* may change due to user interaction.
*/
override fun hashCode(): Int {
return id.hashCode() + wordId.hashCode() + startTime.hashCode()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Task) return false
return id == other.id && wordId == other.wordId && startTime == other.startTime
}
// override fun compareTo(other: Task): Int {
// return compareValuesBy(this, other, { it.nextTime }, { it.timePart })
// }
override fun toString(): String {
return "Task(nextTime='$nextTime', time=$timePart)"
}
}
Select the date part and then select the time part to sort. The second sort operation will be executed only when two elements are equal at the first sort operation. The codes in the question malfunction because they have been not equal at the first sort operation. I share the final functional codes as below.
private var dateFormat = SimpleDateFormat("yyyy-MM-dd")
private var timeFormat = SimpleDateFormat("HH:mm:ss")
fun updateData(data: MutableMap<Task, Word>) {
this.data.clear()
val sortedByDescending = data.keys.sortedWith(
compareByDescending<Task> { selectDate(it) }.thenBy { selectTime(it) })
this.data.addAll(sortedByDescending)
notifyDataSetChanged()
}
private fun selectDate(task: Task): String {
val result = dateFormat.format(task.nextTime.time)
return result
}
private fun selectTime(task: Task): String {
val result = timeFormat.format(task.nextTime.time)
return result
}