fillSpace: distribute remainder
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
function fillSpace(availableSpace: number, items: { min: number, max: number }[]) {
|
||||
if (items.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const middleSize = findMiddleSize(availableSpace, items);
|
||||
return items.map(item => clamp(middleSize, item.min, item.max));
|
||||
const sizes = items.map(item => clamp(middleSize, item.min, item.max));
|
||||
if (middleSize !== Math.floor(availableSpace / items.length)) {
|
||||
distributeRemainder(availableSpace, middleSize, sizes, items);
|
||||
}
|
||||
return sizes;
|
||||
|
||||
function findMiddleSize(availableSpace: number, items: { min: number, max: number }[]) {
|
||||
if (items.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ranges = buildRanges(items);
|
||||
let requiredSpace = items.reduce((acc, item) => acc + item.min, 0);
|
||||
for (const range of ranges) {
|
||||
@@ -50,6 +54,28 @@ function fillSpace(availableSpace: number, items: { min: number, max: number }[]
|
||||
return array;
|
||||
}
|
||||
|
||||
function distributeRemainder(availableSpace: number, middleSize: number, sizes: number[], constraints: { max: number }[]) {
|
||||
const indexes = Array.from(sizes.keys())
|
||||
.filter(i => sizes[i] === middleSize);
|
||||
indexes.sort((a, b) => constraints[a].max - constraints[b].max);
|
||||
|
||||
const requiredSpace = sum(...sizes);
|
||||
let remainder = availableSpace - requiredSpace;
|
||||
let n = indexes.length;
|
||||
for (const i of indexes) {
|
||||
if (remainder <= 0) {
|
||||
break;
|
||||
}
|
||||
const enlargable = constraints[i].max - sizes[i];
|
||||
if (enlargable > 0) {
|
||||
const enlarge = Math.min(enlargable, Math.ceil(remainder / n));
|
||||
sizes[i] += enlarge;
|
||||
remainder -= enlarge;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
type Range = {
|
||||
start: number,
|
||||
end: number,
|
||||
|
||||
@@ -58,7 +58,7 @@ tests.register("fillSpace", 1, () => {
|
||||
{ min: 400, max: 500 },
|
||||
{ min: 10, max: 300 },
|
||||
],
|
||||
expected: [116, 116, 400, 116],
|
||||
expected: [117, 117, 400, 116],
|
||||
},
|
||||
{
|
||||
availableSpace: 750,
|
||||
@@ -98,7 +98,7 @@ tests.register("fillSpace", 1, () => {
|
||||
{ min: 109, max: 800 },
|
||||
{ min: 10, max: 800 },
|
||||
],
|
||||
expected: [114, 93, 93, 93, 93, 93, 110, 110],
|
||||
expected: [114, 93, 93, 93, 93, 93, 111, 110],
|
||||
},
|
||||
{
|
||||
availableSpace: 801,
|
||||
@@ -126,7 +126,7 @@ tests.register("fillSpace", 1, () => {
|
||||
{ min: 109, max: 800 },
|
||||
{ min: 10, max: 95 },
|
||||
],
|
||||
expected: [120, 93, 93, 93, 93, 93, 120, 95],
|
||||
expected: [121, 93, 93, 93, 93, 93, 120, 95],
|
||||
},
|
||||
{
|
||||
availableSpace: 799,
|
||||
@@ -140,7 +140,7 @@ tests.register("fillSpace", 1, () => {
|
||||
{ min: 10, max: 91},
|
||||
{ min: 105, max: 800 },
|
||||
],
|
||||
expected: [79, 107, 107, 107, 107, 107, 79, 105],
|
||||
expected: [80, 107, 107, 107, 107, 107, 79, 105],
|
||||
},
|
||||
{
|
||||
availableSpace: 1029,
|
||||
@@ -184,7 +184,7 @@ tests.register("fillSpace", 1, () => {
|
||||
{ min: 10, max: 600 },
|
||||
{ min: 10, max: 600 },
|
||||
],
|
||||
expected: [204, 199, 199, 199],
|
||||
expected: [204, 200, 200, 199],
|
||||
},
|
||||
{
|
||||
availableSpace: 900,
|
||||
|
||||
Reference in New Issue
Block a user