【问题标题】:How to prevent duplicate elements according to one parameter while sorting for another parameter, Data Structures, Kotlin如何在为另一个参数排序时根据一个参数防止重复元素,数据结构,Kotlin
【发布时间】:2020-06-07 12:51:37
【问题描述】:

假设class Student 带有参数namegradeID

class Student (name: String, grade: String, ID: String) {  
    var _studentID = ID
    var _studentName = name
    var _studentGrade = grade

    //override hashCode(), equals(), compareTo() etc
}

如何根据ID 防止重复条目,同时根据name 自动对它们进行排序?

for 循环中使用ArrayList 来检查重复项然后使用sortBy 函数并非不可能。这种方法也允许我向用户提供反馈。但是,可能有更好的算法或数据结构(即 HashSet、TreeMap 等)来完成这项工作。你有什么推荐的?

附:我也试过 TreeSet。但不知何故,TreeSet 偶尔允许具有相似 ID 的实例进入集合(比如 5 次连续尝试中的 1 次)。你知道这是怎么发生的吗?可能是由于不同的线程在同一数据上运行,还是由于 equals()compareTo() 方法不一致(equals()ID 覆盖,compareTo()name 覆盖)?

【问题讨论】:

    标签: android-studio sorting kotlin data-structures duplicates


    【解决方案1】:

    如果您想维护sorted data setTreeSet 将是最佳选择。因为它为基本操作(添加、删除和包含)提供有保证的log(n) 时间成本。

    为了使用它,您必须通过实现Comparable 为您的类定义natural ordering,或者您必须提供comparator

    在为 TreeSet 实现 Comparable 时,您必须注意一件事,来自 TreeSetComparable 文档

    请注意,由集合维护的顺序(无论是否显式 提供了比较器)必须与equals一致,如果它是 正确实现 Set 接口

    C 类的自然排序据说与 当且仅当 e1.compareTo(e2) == 0 具有相同的布尔值时等于 如 e1.equals(e2)

    现在要以与上述声明一致的方式实现Comparable,您将执行以下操作。

    class Student (name: String, grade: String, ID: String): Comparable<Student>{
        var studentID = ID
        var studentName = name
        var studentGrade = grade
    
        // Use the default equals generated by your IDE, but only take into accout ID field
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false
            other as Student
            if (studentID != other.studentID) return false
            return true
        }
    
        // Whenever you override equals, you also need to override hashCode
        override fun hashCode() = studentID.hashCode()
    
        // Define natural ordering
        override fun compareTo(other: Student): Int {
            if(equals(other)) return 0
            var nameComparison = studentName.compareTo(other.studentName)
            return when(nameComparison){
                // If two objects are equal when compared by name then we sort them by id
                0 -> studentID.compareTo(other.studentID)
                else -> nameComparison
            }
        }
    }
    

    【讨论】:

    • 感谢您的回复。 if (equals(other)) 是一个不错的技巧。在我的代码中是if (studentID == other.studentID) return 0。也许这就是不一致的原因。 when() 部分也是经过深思熟虑的。我写的不是when(),而是else {return (studentName.compareTo(other.studentName))。 Kotlin 不喜欢 return 中的 ifwhen 语句。你知道原因吗?
    • 顺便说一句,我最终使用了一个 ArrayList,在 for 循环中检查类似的元素。这样我就可以检测到已经存在的元素并向用户提供反馈并返回有关它的信息。作为新手读者的旁注,除了答案中提到的之外,TreeSets 还有其他一致性要求(即e1.compareTo(e2) = 0 ---&gt; e2.compareTo(e1) = 0sign(e1.compareTo(e2)) = -sign(e2.compareTo(e1)) 等)
    • 你可以对 TreeSet 做同样的事情,阅读 add 方法的文档,它返回一个布尔值,指示集合是否已经包含指定的元素。您也可以使用包含。与在 ArrayList 中查找元素相比,这些将非常快
    • Jup 但我需要进行比较,因为只有 ID。有没有像 if (studentSet.contains(newStudent.studentID)) 这样的用法?此外,看起来 TreeSet 不使用索引。如何在没有索引的情况下指定相应 studentID 的 studentName?
    猜你喜欢
    • 2020-07-19
    • 1970-01-01
    • 2018-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 2020-12-04
    相关资源
    最近更新 更多