Mover instancias de Set a otro en Scala

En un juego necesito mantener las pestañas de cuál de mis sprites agrupados están en uso. Cuando "activo" múltiples sprites a la vez quiero transferirlos de mi passivePool a activePool ambos de los cuales son inmutables HashSets (ok, voy a estar creando nuevos conjuntos cada vez para ser exactos). Así que mi idea básica es a lo largo de las líneas de:

 activePool ++= passivePool.take(5) passivePool = passivePool.drop(5) 

pero la lectura de la documentación scala supongo que los 5 que tomo podría ser diferente que el 5 que luego caer. Que definitivamente no es lo que quiero. También podría decir algo como:

 val moved = passivePool.take(5) activePool ++= moved passivePool --= moved 

pero como esto es algo que tengo que hacer casi todos los fotogramas en tiempo real en un dispositivo limitado (teléfono Android) Supongo que esto sería mucho más lento, ya que tendré que buscar uno por uno cada uno de los sprites moved de la passivePool .

¿Alguna solución inteligente? ¿O me falta algo básico? Recuerde que la eficiencia es una preocupación principal aquí. Y no puedo usar listas en lugar de conjuntos porque también necesito la eliminación de acceso aleatorio de sprites de activePools cuando los sprites se destruyen en el juego.

No hay nada como benchmarking para obtener respuestas a estas preguntas. Vamos a tomar 100 juegos de tamaño 1000 y dejarlos caer 5 a la vez hasta que estén vacíos, y ver cuánto tiempo toma.

 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 

¿Qué está pasando?

La razón por la que las cosas funcionan de esta manera es que inmutable.HashSet se construye como un hash trie con optimizado (efectivamente O(1) ) agregar y quitar operaciones, pero muchos de los otros métodos no se vuelven a implementar; en su lugar, se heredan de colecciones que no admiten add / remove y por lo tanto no puede obtener los métodos eficientes de forma gratuita. Por lo tanto, en su mayoría reconstruir todo el conjunto hash desde cero. A menos que su conjunto hash tiene sólo un puñado de elementos en él, esto es mala idea. (En contraste con la desaceleración 50-100x con conjuntos de tamaño 1000, un conjunto de tamaño 100 tiene "sólo" una desaceleración 6-10x ….)

Por lo tanto, la línea de fondo: hasta que la biblioteca se ha mejorado, hacerlo de manera "ineficiente". Serás mucho más rápido.

Creo que puede haber un cierto kilometraje en el uso de splitAt aquí, que le devolverá tanto los cinco sprites para moverse y la piscina recortada en una única invocación de método:

 val (moved, newPassivePool) = passivePool.splitAt(5) activePool ++= moved passivePool = newPassivePool 

Puntos de bonificación si puede asignar directamente de nuevo a passivePool en la primera línea, aunque no creo que sea posible en un breve ejemplo en el que está definiendo la nueva variable moved también.

  • Cómo dibujar una imagen de fondo grande con libgdx - las mejores prácticas?
  • ¿Dónde ejecutar algoritmos complejos? Lado del servidor o lado del cliente?
  • Lectura de datos de 4 archivos CSV estáticos en Android: Best Approach?
  • ¿Es una buena idea escribir juegos para móviles en ActionScript3 en lugar de Java / Objective-C?
  • Android: nesting FrameLayouts - ¿cuál es la sobrecarga de rendimiento exacto?
  • ¿El recolector de basura de Android hace una pausa en otras aplicaciones mientras se ejecuta?
  • Desventajas en Multidexing la aplicación de Android
  • Android Ver animación - bajo rendimiento en pantallas grandes
  • Android ViewPager y TabLayout no funcionan rápido
  • Descomprimir archivos de una manera más rápida que usar java.util.zip en Android
  • Android y su lenta webview. Hardware acelerado es buggy
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.