Un sistema que estoy construyendo incluye un conjunto de controles deslizantes de UI (el número varía) cada uno con una escala de 0-100. Por control deslizante me refiero a una interfaz de usuario donde agarras un elemento y lo arrastras hacia arriba y hacia abajo, como un control de volumen. Están conectados por un algoritmo que asegura que siempre suman 100. Entonces, cuando un control deslizante se mueve hacia arriba, los demás se mueven hacia abajo, eventualmente a cero. Cuando uno se mueve hacia abajo, los otros se mueven hacia arriba. En todo momento, el total debe ser 100. Entonces, los controles deslizantes tienen varios valores, pero suman 100%:
----O------ 40
O---------- 0
--O-------- 20
--O-------- 20
--O-------- 20
Si el primer control deslizante luego se mueve hacia ARRIBA de 40 a 70, los otros deben moverse hacia ABAJO en valor (a medida que se arrastra el control deslizante). Tenga en cuenta que tres controles deslizantes cambiaron de 20 a 10, y uno se mantuvo en cero, ya que no puede bajar.
-------O--- 70
O---------- 0
-O--------- 10
-O--------- 10
-O--------- 10
Por supuesto, cuando cualquier control deslizante alcanza 0 o 100, no puede moverse más, que es donde realmente me comienza a doler la cabeza. Entonces, si un control deslizante se mueve más alto, los otros se mueven más abajo, pero cuando alguno de ellos llega a cero, solo los restantes que aún no han llegado a cero pueden moverse más abajo.
Estoy haciendo esto aquí ya que esta pregunta es específica del algoritmo, no de la implementación. FWIW la plataforma es Android Java, pero eso no es especialmente relevante.
El enfoque que tomé con mi primera puñalada fue calcular el cambio porcentual del control deslizante que se movió. Luego dividí ese cambio y lo apliqué (en la otra dirección) a los otros valores del control deslizante. Sin embargo, el problema es que al usar porcentajes y multiplicar, si un control deslizante llega a cero, nunca se puede volver a aumentar desde cero; el resultado neto es que los controles deslizantes individuales se atascan en cero. He usado controles deslizantes con un rango de 0 - 1,000,000 para evitar problemas de redondeo y eso parece ser útil, pero todavía tengo que crear un algoritmo que maneje bien todos los escenarios.
fuente
Respuestas:
Algoritmo codicioso
Cuando un control deslizante se mueve hacia arriba (abajo), todos los demás deben moverse hacia abajo (arriba). Cada uno tiene algo de espacio que puede mover (para abajo, su posición, para arriba: 100 posiciones).
Entonces, cuando se mueve un control deslizante, tome los otros controles deslizantes, ordénelos por el espacio que pueden mover y simplemente repítelos.
En cada iteración, mueva el control deslizante en la dirección necesaria (total para mover a la izquierda / controles deslizantes a la izquierda en la cola) o la distancia que puede moverse, lo que sea menor.
Esto es de complejidad lineal (ya que puede usar la misma cola ordenada una y otra vez, una vez que se ha ordenado).
En este escenario, los controles deslizantes no se atascan, todos intentan moverse tanto como pueden, pero solo hasta su parte justa.
Movimiento ponderado
Un enfoque diferente sería sopesar el movimiento que necesitan hacer. Creo que esto es lo que trató de hacer, a juzgar por su declaración "los controles deslizantes se atascan en 0". En mi humilde opinión, esto es más natural, solo necesitas hacer más ajustes.
Especulando nuevamente, diría que intentas sopesar los movimientos de los diferentes controles deslizantes por su posición (Esto se traduciría directamente en tu problema atascado en 0). Sin embargo, tenga en cuenta que puede ver la posición del control deslizante desde diferentes direcciones, desde el principio o desde el final. Si pesa por posición desde el principio al disminuir y posición desde el final al aumentar, debe evitar su problema.
Esto es bastante similar en terminología a la parte anterior: no evalúe el movimiento a realizar por la posición de los controles deslizantes, evalúe el espacio que les queda para moverse en esa dirección.
fuente
El enfoque que tomaría es ligeramente diferente e implica el uso de una representación interna diferente de cada control deslizante.
cada control deslizante puede tomar cualquier valor de 0..100 (X) que se utiliza como factor de ponderación para ese control deslizante (no un%)
sume todos los valores del control deslizante para obtener la cifra total (T)
para determinar el valor mostrado de cada control deslizante, use REDONDO (X * 100 / T)
cuando un control deslizante se mueve hacia arriba o hacia abajo, solo cambia el valor de un control deslizante ; la ponderación de ese control deslizante aumentará o disminuirá en relación con todos los demás controles deslizantes, y el cálculo anterior garantizará que el cambio a todos los otros controles deslizantes se distribuya de la manera más uniforme posible.
fuente
Creo que está complicando demasiado las cosas al intentar ajustar el valor actual en un porcentaje del cambio del control deslizante 'movido', que le da porcentajes de porcentajes, lo que está introduciendo errores de redondeo.
Como sabes que solo estás tratando con un valor total de 100, mantendría las cosas como números enteros y trabajaría hacia atrás desde el 100, evitando cualquier problema serio con el redondeo. (En el siguiente ejemplo, manejo cualquier redondeo como enteros enteros al final)
Mi técnica sería establecer los controles deslizantes como simples 0-100. Reste el valor 'nuevo' de 100 para calcular cuánto redistribuir, distribuya eso entre los otros controles deslizantes de acuerdo con su peso, luego limpie)
Este no es, hasta donde yo sé, un código de Android válido: p
Esto debería manejar intrínsecamente cualquier valor 0 o 100
fuente
¿Qué pasa con el enfoque Round Robin? Cree una transacción que asegure que agregar valor a un control deslizante se reducirá de su par. y viceversa.
Luego, cada vez que cambie un control deslizante, ejecute la transacción con un control deslizante de pares diferente (crearía un iterador que devolvería el control deslizante de pares por turnos). Si el control deslizante de pares es cero, continúe con el siguiente.
fuente
Solo para elaborar sobre la gran respuesta del algoritmo codicioso de @Ordous. Aquí hay un desglose de los pasos.
fuente
Una técnica simple es calcular los porcentajes de los valores del control deslizante en relación con la suma de los valores del control deslizante y luego reasignar los valores del control deslizante a los porcentajes calculados respectivos. de esta manera los valores del control deslizante se reajustarán, por ejemplo
Aunque introduce un error de redondeo, puede manejarse en caso de que necesitemos los valores de los controles deslizantes para sumar exactamente y siempre hasta 100.
He configurado un violín para demostrar esto usando angularjs. Por favor visite demo
fuente