У меня есть макет, в котором:
- Страница разбита на столько фиксированной ширины столбцов , сколько может поместиться на ней.
- Рядов ящики помещаются в эти столбцы , каждый из которых охватывает целое число столбцов .
- Каждый ящик имеет используемый весопределить их диапазон столбцов (IE: если строка имеет 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
не станет меньше или равна * 1047.* (с учетом любых округленных до 0,5 пар)
Эта функция имеет две основные проблемы:
- Она ужасно неэффективна (как
totalValues
, так и * 1055).* должен пройти через массив внутри основного цикла функции) - Это неправильно способствует уменьшению первого "наибольшего значения", которое он находит.
Для иллюстрации пункта (2) рассмотримследующее:
weightedIntegerValues([1, 2, 4, 3], 5); // [1, 1, 1, 2]
Найдена весовая функция rокругленные значения [1, 1, 2, 2]
, определяемые как превышающие желаемую сумму 5, и вычитаем 1 из первого наибольшего найденного значения (по индексу 3), но на самом деле нам хотелось бы вычесть 1 из индекса 4, который до этого был 1,5округляя, давая нам [1, 1, 2, 1]
.
Мои вопросы следующие:
- Можно ли это сделать лучше, чем N 2 ?Было бы здорово уменьшить его до N.
- Есть ли какой-нибудь простой и более математический способ отдавать предпочтение числам, округленным до 0,5, вместо того, чтобы отдавать предпочтение значениям lefter или правильнее?
- Есть какой-то аккуратный CSS, который может обработать этот вариант использования для меня?Flex-box подходит довольно близко, но пока что не совсем подходит для меня (возможно, это уже совсем другой вопрос).