You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中ArrayList<HashSet<data class>>的reduce函数处理子集时失效

解决ArrayList<HashSet>交集函数处理子集失效的问题

我一眼就看出问题出在你用retainAll的方式上——这个方法会直接修改调用它的集合本身,而不是返回一个新集合。你的reduce操作里,acc其实是原ArrayList中第一个HashSet的引用,调用acc.retainAll(it)后,原集合的内容被永久改变了。这就导致当你后续再处理这个ArrayList的子集时,里面的集合已经不是最初的原始数据,自然算不出正确的交集。

修复方案:操作集合的副本而非原集合

我们需要在每次交集计算时,基于原集合的副本进行操作,避免破坏原始数据。这里用fold来实现会更清晰,因为可以明确初始化一个独立的副本:

fun intersection(data: ArrayList<HashSet<Protein>>): HashSet<Protein> {
    // 处理空输入的边界情况
    if (data.isEmpty()) return HashSet()
    
    // 以第一个集合的副本作为初始累加器,完全独立于原集合
    return data.drop(1).fold(HashSet(data.first())) { acc, currentSet ->
        // 在副本上执行交集操作,不影响原数据
        acc.retainAll(currentSet)
        acc
    }
}

为什么这样能解决问题?

  1. 避免修改原集合:HashSet(data.first())创建了第一个集合的独立副本(对于你的Protein类,因为是data class且属性都是不可变类型,浅拷贝足够),后续所有操作都在这个副本上进行,原ArrayList中的HashSet内容完全不受影响。
  2. 正确处理子集场景:不管你传入的是整个ArrayList还是它的某个子集(比如data.subList(0,3)),原始集合的数据都不会被改动,每次计算都是基于当前传入的原始子集数据进行的。

额外提示

如果你坚持要用reduce,也可以修改为每次创建新集合:

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

不过这种方式每次reduce都会创建新集合,性能上比fold略差一点,因为fold只需要初始化一次副本。

内容的提问来源于stack exchange,提问作者PeptideWitch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:58:20