Tengo un pequeño dolor de cabeza por un problema con respecto a una forma eficiente de distribuir una cantidad fija de puntos de manera uniforme entre n artículos que tienen diferentes costos y límites. Los costos no aumentan con cada artículo.
Digamos que tengo 3 artículos:
| Nombre | Costo | Límite |
|---|---|---|
| A | 25 | 220 |
| B | 30 | 20 |
| C | 50 | 60 |
Además tenemos Puntos fijos: 5000 . Quiero saber cuantas veces puedo comprar cada uno. Mi solución actual ejecuta un ciclo y deduce el costo de los puntos hasta que se alcanzan todos los límites o se agotan los puntos. http://jsfiddle.net/nasc8rfL/
var points = 5000; var costA = 25; var costB = 30; ... var limitA = 220; ... var maxA = 0; while (points > 0){ if (points >= costA && limitA > 0){ points -=costA; limitA -=1; maxA +=1; }; if (points >= costB && limitB > 0){ points -=costB; limitB -=1; maxB +=1; }; if (points >= costC && limitC > 0){ points -=costC; limitC -=1; maxC +=1; }; if((points < costA) and (points < costB) and (points <costC)) break; } console.log(maxA,maxB,maxC);Eventualmente, no permanecerá en A, B, C sino en un número variable de elementos (no más de 20), por lo que recorrería cada elemento en lugar de 3 IF.
En realidad, no tengo que deducir puntos, solo tengo que saber cuántos de cada artículo se pueden comprar. Siento que me estoy perdiendo algo y hay una manera más fácil de determinar el número de cada uno.
He pensado en ponderarlos en función de sus límites, pero mi cabeza no quiere trabajar conmigo y estoy bastante atascado en este momento.
Además, soy un principiante en javascript, por lo que si tienen algunos consejos para obtener el bucle que se muestra más rápido o más conveniente, tal vez con algo como
function func(arr){ arr.forEach(x=>{doSomething();})sería más que feliz.
Tu enfoque no es malo. El algoritmo se puede acelerar un poco por
const points = 5000; const items = [ {name: "A", cost: 25, limit: 220}, {name: "B", cost: 30, limit: 60}, {name: "C", cost: 50, limit: 20}, ]; let amounts = Object.fromEntries(items.map(i => [i.name, 0])); let available = items; let toSpend = points; do { available = available.filter(i => amounts[i.name] < i.limit && i.cost <= toSpend); const maxAmount = Math.max(1, Math.floor(toSpend / available.reduce((s, i) => s+i.cost, 0))); for (const a of available) { const amount = Math.min(maxAmount, a.limit - amounts[a.name]); if (amount * a.cost <= toSpend) { amounts[a.name] += amount; toSpend -= amount * a.cost; } else { break; } } } while (available.length); console.log(amounts); console.log(`Leftover: ${toSpend}`);