我也需要一个简单的BiMap 实现,因此决定创建一个名为bimap 的小库。
BiMap 的实现非常简单,但它包含一个棘手的部分,即一组条目、键和值。我将尝试解释实现的一些细节,但您可以在 GitHub 上找到完整的实现。
首先,我们需要为不可变和可变BiMaps 定义接口。
interface BiMap<K : Any, V : Any> : Map<K, V> {
override val values: Set<V>
val inverse: BiMap<V, K>
}
interface MutableBiMap<K : Any, V : Any> : BiMap<K, V>, MutableMap<K, V> {
override val values: MutableSet<V>
override val inverse: MutableBiMap<V, K>
fun forcePut(key: K, value: V): V?
}
请注意,BiMap.values 返回的是 Set,而不是 Collection。当BiMap 已经包含给定值时,BiMap.put(K, V) 也会引发异常。如果您想用(K1, V2) 替换对(K1, V1) 和(K2, V2),您需要调用forcePut(K, V)。最后你可能会得到一个反向的BiMap 来按值访问它的键。
BiMap 是使用两个常规映射实现的:
val direct: MutableMap<K, V>
val reverse: MutableMap<V, K>
可以通过交换direct 和reverse 映射来创建反向BiMap。我的实现提供了一个不变的bimap.inverse.inverse === bimap,但这不是必需的。
如前所述,forcePut(K, V) 方法可以将 (K1, V1) 和 (K2, V2) 替换为 (K1, V2)。首先,它检查K1 的当前值是什么,并将其从reverse 映射中删除。然后它找到值V2 的键并将其从direct 映射中删除。然后该方法将给定的对插入到两个映射中。这是它在代码中的样子。
override fun forcePut(key: K, value: V): V? {
val oldValue = direct.put(key, value)
oldValue?.let { reverse.remove(it) }
val oldKey = reverse.put(value, key)
oldKey?.let { direct.remove(it) }
return oldValue
}
Map 和MutableMap 方法的实现非常简单,所以我不会在这里提供它们的详细信息。他们只是在两个地图上执行操作。
最复杂的部分是entries、keys和values。在我的实现中,我创建了一个Set,它将所有方法调用委托给direct.entries,并处理条目的修改。每次修改都发生在 try/catch 块中,以便在引发异常时 BiMap 保持一致状态。此外,迭代器和可变条目被包装在类似的类中。不幸的是,它使得对条目的迭代效率大大降低,因为在每个迭代步骤中都会创建一个额外的 MutableMap.MutableEntry 包装器。