我试图从一个巨大的哈希图中创建一个子哈希图,而不复制原始哈希图。
当前我使用这个:
i
这花费了我目前算法的50%左右。因为java确实经常计算val map = hashMapOf<Job, Int>()
val copy = HashMap(map)
listToRemoveFromCopy.forEach { copy.remove(it) }
的哈希值。
我只希望在新变量中将job
减去map
,而不要从原始列表中删除listToRemoveFromCopy
元素。
有人知道吗?
感谢帮助
答案 0 :(得分:1)
首先,您需要缓存Job
的哈希码,因为如果无法拥有Job
对象的集合或映射,则使用的任何方法都将效率低下以最快的速度。
希望,使它成为哈希码的部分是不可变的,否则不应将其用作键。在地图或集合中使用键时,突变键非常危险。您应该在第一次调用hashCode()
时将其缓存,以免在此之前不会产生费用,除非您确定始终需要它。
然后将listToRemoveFromCopy
更改为Set
,以便可以多种方式有效地使用它。您需要先执行之前的步骤。
现在您有多个选择。最有效的是:
Guava具有实用程序功能Maps.filterKeys
,可将视图返回到地图中,并且您可以创建一个谓词,该谓词与要删除的项Set
相对。
val removeKeys = listToRemoveFromCopy.toSet()
val mapView = Maps.filterKeys(map, Predicates.not(Predicates.in(removeKeys)))
但是请务必注意视图上的某些方法不是很有效。如果您避免使用这些方法,这将是效果最好的选项:
许多过滤后的地图方法(例如size())会遍历基础地图中的每个键/值映射,并确定哪个满足过滤条件。如果不需要实时取景,则复制过滤后的地图并使用副本可能会更快。
如果您需要制作副本,则可以采用以下几种方法:
在地图上使用filterKeys
一次即可创建一个新地图。如果删除列表可能在总键中占较大比例,则这很好。
val removeKeys = listToRemoveFromCopy.toSet()
val newMap = map.filterKeys { it !in removeKeys }
您应该注意的另一个诱人的选项是减号-
,该运算符将复制整个地图,然后将其删除。它可以按原样使用listToRemoveFromCopy
,而不必将其作为一个集合,但是完整的地图副本可能会抵消其好处。因此,除非删除列表中只有一小部分键,否则不要这样做。
val newMapButSlower = map - listToRemoveFromCopy
您可以根据地图大小与删除列表大小之间的比率来选择一个模型,而不是另一个模型,找到一个适合您“巨大”的断点。
可以在地图中添加自己的视图以避免复制,但并非无关紧要(因此,我的意思是非常复杂)。您重写的每个方法都必须始终执行正确的操作(包括地图自己的hashCode
和equals
),并且必须围绕键集和值创建其他视图。 entrySet
很讨厌正确。在尝试您自己的(上面的番石榴或其他番石榴)之前,我会寻找一种预先编写的解决方案。零拷贝模型将是最有效的解决方案,但是代码最多,如果“巨大”意味着需要大量处理时间,我将在相同情况下执行该操作。如果您误解了实施合同的任何部分,那么使用这种方法会有很多错误。
您可以使用一种在操作项目时保持size
属性的Guava解决方案来包装它,因此对于这种情况是有效的。如果您知道原始地图是只读的,则还可以编写一个更有效的解决方案。有关想法,请查看FilteredKeyMap的Guava实现及其祖先AbstractFilteredMap。
总之,您的哈希码缓存可能会为您带来最大的努力成果。从那里开始。您甚至需要使用番石榴方法。
答案 1 :(得分:0)
您可以使用filterKeys
功能。只会迭代地图一次
val copy = map.filterKeys { it !in listToRemoveFromCopy }
答案 2 :(得分:0)
除了Axel的直接答案:
可以优化计算作业的哈希码吗?如果无法加快计算速度,是否可以缓存结果? (对此有很多先例,包括java.lang.String
。)或者,如果该类不在您的控制之下,您是否可以创建一个覆盖哈希码计算的委托/包装程序?