Java/Kotlin:通过class ID求多个HashSet的交集

Java/Kotlin: Finding the intersection of multiple HashSets by class ID

我在查找包含数据 Class 的散列集数组的交集时遇到问题(我想通过标识符进行交集):

class Protein(val id: String, val score: Double, val molw: Double, val spc: Int)

我已经从 .csv 文件中提取了一些数据到这种类型的结构中:

ArrayList<HashSet<Protein>>

所以我有六个数组列表[每个 csv 一个],每个包含一个包含数千个蛋白质结构的散列集。到目前为止,这是我尝试获得基于 common Protein.id:

的交集 HashSet 的方法
fun intersection(data: ArrayList<HashSet<Protein>>): HashSet<Protein> {

val intersectionSet = HashSet<Protein>(data[0])

for (i in 1..data.size) {
    intersectionSet.retainAll(data[i])
}
return intersectionSet
}

这个 returns 一个空列表,这是有道理的,因为它试图与 Protein 对象相交并匹配每个标准作为一个整体。

如何调用 data[i].id 作为我的交集标准?我对 Kotlin 和数据还很陌生 类 :)

如果您在 Protein class 中添加 hashCodeequals 函数的定义如下,那么 HashSet 将能够适当地使用 id 字段检查交叉点。

class Protein(val id: String, val score: Double, val molw: Double, val spc: Int) {
  override fun hashCode() = id.hashCode()
  override fun equals(other: Any?) = other?.let { id == (it as Protein).id } ?: false
}

您可能还想将 intersection 函数中的循环范围更改为 1..(data.size-1) 而不是 1..data.size 以避免越界。或者,您可以按如下方式编写它的功能:

fun intersection(data: ArrayList<HashSet<Protein>>): HashSet<Protein> {
  return data.reduce { acc, it -> acc.apply { retainAll(it) } }
}

为了简化给出的答案,您可以使用apply:

return data.reduce { acc, it -> acc.apply { retainAll(it) } }

请注意,如果您不想依赖于输入成为哈希集,您可以执行以下操作:

fun <T> multiIntersect(data: Collection<Set<T>>) = 
    HashSet(data.minBy { it.size }!!).apply {  data.forEach { retainAll(it) } }

从最小的集合开始,您可以节省大量的运行时间,因为检索集合的大小可以在常量时间内完成,因为它保存在对象的字段中。