从两个 KOTLIN获取不常见的元素



我有两个相同模型类(STUDENT(的列表,下面给出了示例学生对象结构,

{
  "_id": "5a66d78690429a1d897a91ed",
  "division": "G",
  "standard": "X",
  "section": "Secondary",
  "lastName": "Sawant",
  "middleName": "Sandeep",
  "firstName": "Shraddha",
  "pin": 12345,
  "isEditable": true,
  "isTracked": false
}
一个列表有

3 个对象,另一个有 2 个。假设列表 A 有 1、2、3 名学生,列表 B 有 1、2 名学生

所以我的问题是否有任何内置函数可以通过仅比较 id 来获取不常见的元素?如果没有,我该如何解决这个问题。

仅供参考,以下是我为解决而采取的两种方法,但惨遭失败。

方法1.

internal fun getDistinctStudents(studentsList: List<Students>, prefStudents: List<Students>): List<Students> {
    val consolidated = prefStudents.filter {
        prefStudents.any { students: Students -> it._id == students._id }
    }
    return prefStudents.minus(consolidated)
}

方法2.

internal fun getDistinctStudents(studentsList: List<Students>, prefStudents: List<Students>): List<Students> {
    val consolidatedStudents = studentsList + prefStudents
    val distinctStudents = consolidatedStudents.distinctBy{ it._id }
    return prefStudents.minus(distinctStudents)
}

任何形式的帮助将不胜感激。

谢谢

一种更 Kotlin 的方式来实现 Ahmed Hegazy 发布的内容。地图将包含元素列表,而不是键和计数。

使用 HashMap 和 Kotlin 内置。 groupBy创建一个映射,其中包含 Lambda 中定义的键(在本例中为 id(和项目列表(此方案的列表(

然后筛选出列表大小不是 1 的条目。

最后,将其转换为单个学生列表(因此 flatMap 调用(

val list1 = listOf(Student("1", "name1"), Student("2", "name2"))
val list2 = listOf(Student("1", "name1"), Student("2", "name2"), Student("3", "name2"))
val sum = list1 + list2
return sum.groupBy { it.id }
    .filter { it.value.size == 1 }
    .flatMap { it.value }
我知道

这是一个旧帖子,但我相信有一个更整洁、更短的解决方案。请参阅下面的示例,使用Mikezx6r的数据,其答案已在上面接受。

val list1 = listOf(Student("1", "name1"), Student("2", "name2"))
val list2 = listOf(Student("1", "name1"), Student("2", "name2"), Student("3", "name2"))
val difference = list2.toSet().minus(list1.toSet())
<</div> div class="one_answers">

如果你有两个列表,其中元素是由某种id(item.id(标识的,那么你可以执行以下操作:

fisrtList.filter { it.id !in secondList.map { item -> item.id } }

我假设 firstList 和 secondList 自然包含相同类型的对象。

这是一个扩展函数,基本上可以做你想要的。它假设元素E知道如何识别,例如通过示例中的Student._id

infix fun <E> Collection<E>.symmetricDifference(other: Collection<E>): Set<E> {
    val left = this subtract other
    val right = other subtract this
    return left union right
}

下面是如何使用它的示例:

val disjunctiveUnion: List<Student> = listA symmetricDifference listB

我为它编写的示例测试用例:

@Test
fun `symmetric difference with one of either set`() {
    val left = listOf(1, 2, 3)
    val right = listOf(2, 3, 4)
    val result = left symmetricDifference right
    assertEquals(setOf(1, 4), result)
}

这是使用 HashMap 的解决方案,代码可能会更好,但我对 kotlin 很陌生

fun getDistinctStudents(studentsList: List<Student>, prefStudents: List<Student>): List<Student> {
    val studentsOccurrences = HashMap<Student, Int>()
    val consolidatedStudents = studentsList + prefStudents
    for (student in consolidatedStudents) {
        val numberOfOccurrences = studentsOccurrences[student]
        studentsOccurrences.put(student, if(numberOfOccurrences == null) 1 else numberOfOccurrences + 1)
    }
    return consolidatedStudents.filter { student -> studentsOccurrences[student] == 1 }
}

您的学生类应该是数据类,或者至少覆盖哈希代码并等于用作键。

在有人提出一个更整洁、更短的解决方案之前,这里有一个我认为很容易阅读的解决方案:

internal fun getDistinctStudents(studentsList: List<Students>, prefStudents: List<Students>): List<Students> {
    val studentsIds = studentsList.map { it._id }          // [ 1, 2, 3 ]
    val prefStudentIds = prefStudents.map { it._id }       // [ 1, 2 ]
    val commonIds = studentsIds.intersect(prefStudentIds)  // [ 1, 2 ]
    val allStudents = studentsList + prefStudents      // [ Student1, Student2, Student3, Student1, Student2 ]
    return allStudents.filter { it._id !in commonIds } // [ Student3 ]
}

如果您有非常多的学生(数百人(,请考虑对各个步骤使用序列,也许在连接最后两个列表之前进行过滤也会有所帮助:

val filteredStudents = studentsList.filter { it._id !in commonIds }
val filteredPrefStudents = prefStudents.filter { it._id !in commonIds }
return filteredStudents + filteredPrefStudents

编辑:请看这个答案。

最后,

在对 Kotlin 文档进行一些搜索后,我有了解决方案。 我正在寻找的功能是filterNot

这是我尝试过的完整解决方案。

internal fun getDistinctStudents(studentsList: List<Students>, prefStudents: List<Students>): List<Students> {
    return prefStudents.filterNot { prefStudent ->
         studentsList.any {
             prefStudent._id == it._id
         }
    } 
}

这返回了不常见的元素。

现在在

移动设备上,所以我无法测试它,但这可能适用于您的需求。使用从 stdlib https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/subtract.html 中减去

internal fun getDistinctStudents(studentsList: List<Students>, prefStudents: 
List<Students>): List<Students> {
    return prefStudents.subtract(studentList) + studentList.subtract(prefStudents)
}

最新更新