在游戏中,我需要密切关注我的哪些精灵正在使用中。当我同时“激活”多个精灵时,我想将它们从passivePool
转移到activePool
,这两个都是不可变的HashSets(好的,我每次都会创建新的精确集)。所以我的基本想法是:
activePool ++= passivePool.take(5)
passivePool = passivePool.drop(5)
但是阅读scala文档我猜我所采取的5可能与5我然后丢弃的不同。这绝对不是我想要的。我也可以这样说:
val moved = passivePool.take(5)
activePool ++= moved
passivePool --= moved
但由于这是我需要在有限的设备(Android手机)上实时完成每一帧的事情,我想这会慢得多,因为我必须逐个搜索moved
来自passivePool
的精灵。
任何聪明的解决方案?还是我错过了一些基本的东西?请记住效率是这里的主要关注点。而且我不能使用Lists而不是Sets,因为当游戏中的精灵被破坏时,我还需要从activePools中随机访问精灵。
答案 0 :(得分:6)
没有像基准测试来获得这些问题的答案。让我们取100套1000的尺寸,一次放下5只,直到它们为空,看看需要多长时间。
passivePool.take(5); passivePool.drop(5) // 2.5 s
passivePool.splitAt(5) // 2.4 s
val a = passivePool.take(5); passivePool --= a // 0.042 s
repeat(5){ val a = passivePool.head; passivePool -= a } // 0.020 s
发生了什么事?
事情以这种方式工作的原因是immutable.HashSet被构建为具有优化(有效O(1)
)添加和删除操作的哈希trie,但许多其他方法没有重新实现;相反,它们继承自不支持添加/删除的集合,因此无法获得免费的有效方法。因此,它们主要从头开始重建整个哈希集。除非你的哈希集中只有少数元素,否则这是个坏主意。 (与套装尺寸为1000的50-100x减速相比,一套100的尺寸“仅”减速6-10倍......)
所以,底线:直到库得到改进,以“效率低下”的方式进行。你将 更快。
答案 1 :(得分:4)
我认为在这里使用splitAt
可能会有一些里程,这将在一次方法调用中返回要移动的五个精灵和修剪池:
val (moved, newPassivePool) = passivePool.splitAt(5)
activePool ++= moved
passivePool = newPassivePool
如果您可以在第一行直接分配回passivePool
,则可以获得奖励积分,但我不认为在您定义新变量moved
的简短示例中也是如此。