math - 将加权值计算为整数以进行布局
问题描述
我有一个布局,其中:
- 该页面被分成尽可能多的固定宽度列,以适应它。
- 行的框适合这些列,每个跨越多个列。
- 每个框都有一个权重,用于确定它们的列跨度(即:如果一行有 6列和 2 个权重为 1 和 2 的框,则框的列跨度分别为 2 和 4)。
如果允许小数列跨度,这将很简单(将每个权重乘以列数并除以总权重),但将其分解为整数变得更加困难。这就是我想出的:
function weightedIntegerValues(weights, total) {
const totalWeight = totalValues(weights);
const weightedValues = weights.map(weight => Math.round(total * weight / totalWeight));
for (let totalValue = totalValues(weightedValues); totalValue > total; totalValue = totalValues(weightedValues))
subtractOneFromHighest(weightedValues);
return weightedValues;
}
为简洁起见,我省略了以下功能:
totalValues
- 获取数组中所有值的总和subtractOneFromHighest
- 找到数组中的最大值并从中减去 1(就地修改数组)
该函数的工作原理如下:
- 如上所述计算加权值,但随着每个值的进行四舍五入
- 不断地从最大值中减去 1,
weightedValues
直到总和weightedValues
小于或等于total
(考虑任何四舍五入的 0.5 对)
这个函数有两个主要问题:
- 它的效率非常低(两者
totalValues
都subtractOneFromHighest
必须循环遍历函数主循环内的数组) - 它错误地倾向于减少它找到的第一个“最高值”。
为了说明第 (2) 点,请考虑以下内容:
weightedIntegerValues([1, 2, 4, 3], 5); // [1, 1, 1, 2]
加权函数找到 的四舍五入值[1, 1, 2, 2]
,确定它大于所需的总和 5,并从它找到的第一个最大值(在索引 3 处)减去 1,但实际上我们希望从索引 4 中减去 1,即 1.5在四舍五入之前,给我们[1, 1, 2, 1]
.
我的问题如下:
- 这可以做得比 N 2更好吗?能降到N就好了。
- 是否有一些简单且更数学的方法来支持四舍五入到 0.5 的数字,而不是支持更左或更右的值?
- 是否有一些整洁的 CSS 可以为我处理这个用例?Flex-box 非常接近,但还没有完全符合我的要求(这可能是另一个问题)。
解决方案
这是一种基于此答案模糊地实现此目的的方法:
function weightedIntegerValues(weights, total) {
let flooredValues = [];
const weightSum = weights.reduce((sum, item) => {
return sum + valueFunc(item);
}, 0);
let flooredSum = 0
weights.forEach((weight, i) => {
const weighted = total * weight / weightSum
const floored = Math.floor(weighted);
flooredValues.push({
floored: floored,
diff: weighted - floored,
index: i
});
flooredSum = flooredSum + flooredValues[i].floored;
});
flooredValues = flooredValues.sort((a, b) => b.diff - a.diff);
const difference = total - flooredSum;
for (let i = 0; i < difference; i++) {
flooredValues[i].floored += 1;
}
return flooredValues.sort((a, b) => a.index - b.index).map(v => v.floored);
}
推荐阅读
- html - 使用 chrome 扩展从无序列表中删除列表项
- android - 问答 在不同的片段中获取单独的 ViewModel 实例
- python - 用 Beatifulsoup 试吃
- sql - 在where子句中的SQL错误未知列?
- c# - 聊天框不工作 c#,Visual Studio,Winforms,Bunifu UI
- javascript - 来自后端的 Vue.js 图像数组作为对象数组返回到前端
- python - 为什么在 Python 中使用 Ray 并行化任务时会出现 PicklingError?
- node.js - AWS DynamoDB 条件获取
- python-3.x - 数值作为字符串并转换为实际数值
- shell - awk:解析文件时丢失数据