我有两个相同模型类的列表(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)
}
任何形式的帮助将不胜感激。
谢谢
答案 0 :(得分:8)
更多Kotlin实现Ahmed Hegazy发布的方式。地图将包含元素列表,而不是键和计数。
使用HashMap和Kotlin内置插件。 groupBy
创建一个Map,其中包含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 }
答案 1 :(得分: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
修改:请参阅this answer instead。
答案 2 :(得分:1)
这是使用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 }
}
您的学生班级应该是数据类,或至少覆盖哈希码和等于用作密钥。
答案 3 :(得分:1)
最后,经过对Kotlin文档的一些搜索,我得到了解决方案。我正在寻找的功能是filterNot
这是我尝试的完整解决方案。
internal fun getDistinctStudents(studentsList: List<Students>, prefStudents: List<Students>): List<Students> {
return prefStudents.filterNot { prefStudent ->
studentsList.any {
prefStudent._id == it._id
}
}
}
返回了不常见的元素。
答案 4 :(得分:1)
现在在移动设备上,所以我无法测试它,但这可能适合您的需要。 使用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)
}
答案 5 :(得分:1)
这是一个扩展功能,基本上可以完成您想要的操作。假设元素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)
}
答案 6 :(得分:1)
如果您有两个列表,则在其中标识元素,例如通过某种ID(item.id),您可以执行以下操作:
fisrtList.filter { it.id !in secondList.map { item -> item.id } }
我假设firstList和secondList自然包含相同类型的对象。
答案 7 :(得分:0)
我知道这是一个过时的帖子,但我相信有一个更简洁,更短的解决方案。使用 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())