Kotlin中HashMap.keySet()调用报错(公共调用相关),求交集方案
首先来说你遇到的编译错误:
你代码里的control.keySet().retainAll(treatment.keySet())返回的是一个Boolean值(用来表示集合是否被修改),而不是新的HashSet,所以直接把它赋值给combineddata会导致类型不匹配。另外,HashMap.keySet()返回的集合是和原HashMap绑定的可变集合,直接调用retainAll会修改原HashMap的键集合,这大概率不是你想要的行为。
第一步:修复编译错误,正确获取重叠键
正确的做法是先复制一份原keySet到独立的可变集合,再调用retainAll来筛选重叠元素:
fun dottest(control: HashMap<UniqueProtein, UniqueProtein>, treatment: HashMap<UniqueProtein, UniqueProtein>) { // 复制control的所有键到新的HashSet,避免修改原HashMap val overlappingKeys = HashSet(control.keys) // 只保留同时存在于treatment中的键 overlappingKeys.retainAll(treatment.keys) // 后续可以使用overlappingKeys做处理 }
第二步:解决潜在的逻辑问题(关键!)
虽然你用了data class,但这里有个隐藏的坑:DoubleArray是引用类型,data class自动生成的equals和hashCode会用引用相等来比较r字段,而不是比较数组的内容。这意味着如果两个UniqueProtein对象的id、spc都相同,r数组的内容也相同但引用不同,它们会被HashMap认为是不同的键,导致你找不出真正的重叠项。
解决这个问题有两种方案:
方案1:改用List<Double>代替DoubleArray
List的equals和hashCode默认是基于内容比较的,所以只需要修改data class的定义:
data class UniqueProtein(var id: String, var spc: Int, var r: List<Double>)
这样data class自动生成的equals/hashCode就能正确比较所有字段的内容,HashMap的key判断就符合预期了。
方案2:手动重写equals和hashCode(如果必须用DoubleArray)
如果你因为性能或其他原因必须保留DoubleArray,可以手动重写这两个方法,用数组的内容来判断相等性:
data class UniqueProtein(var id: String, var spc: Int, var r: DoubleArray) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as UniqueProtein if (id != other.id) return false if (spc != other.spc) return false // 用contentEquals比较数组内容 if (!r.contentEquals(other.r)) return false return true } override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + spc // 用contentHashCode基于数组内容生成哈希值 result = 31 * result + r.contentHashCode() return result } }
这样修改后,HashMap就能正确识别内容相同的UniqueProtein对象为同一个key,你的重叠键查找逻辑才能真正生效。
内容的提问来源于stack exchange,提问作者PeptideWitch

