#javascript #math #range #sequence
#javascript #математика #диапазон #последовательность
Вопрос:
Я пытаюсь взять столбец, заполненный числами, и использовать значения min и max для создания списка диапазонов фильтров, по которым пользователь может фильтровать таблицу. Использование наивного подхода приводит к тому, что трудно обрабатывать диапазоны чисел, и я бы предпочел иметь круглые числа, которые могли бы работать независимо от значений min / max.
Я видел этот вопрос в нескольких местах и думаю, что лучший ответ, который я нашел до сих пор, — это ответ таблицы чисел Стюарта Эйнсворта, но я хотел бы иметь очень круглые шаги.
Например, если мне нужно сгенерировать 4 диапазона от 0 до 100000, числа будут:
0 - 25000
25000 - 50000
50000 - 75000
75000 - 100000
Однако, если мои min и max являются нечетными числами, мне может быть неудобно использовать диапазоны.
Пример: если мне нужно сгенерировать 5 диапазонов от -1234 до 4321, диапазоны будут:
-1234 - -123
-123 - 988
988 - 2099
2099 - 3210
3210 - 4321
Я бы предпочел такие диапазоны, как:
-1234 - 0 -1234 - 0 -1234 - -100
0 - 1000 0 - 1000 -100 - 1000
1000 - 2100 1000 - 2000 1000 - 2100
2100 - 3200 2000 - 3000 2100 - 3200
3200 - 4321 3000 - 4321 3200 - 4321
Или что-то подобное. Диапазоны должны быть близки по размеру друг к другу, но гораздо важнее, чтобы числа было легко просматривать и использовать.
Комментарии:
1. «Арифметическая прогрессия» решит эту проблему. Очевидно, пользовательская функция, которая принимает значение и возвращает нужное вам значение. Может потребоваться две функции. Один для нижней границы значения и один для верхней. Я вскоре опубликую решение, если смогу заставить его работать
2. @GetSet, не так ли? Разве арифметическая прогрессия не была бы фиксированным диапазоном, в то время как OP проявил интерес к размытию чисел / диапазона, чтобы легче усваивать значения минимумов и максимумов.
3. @SpencerD тем не менее, некоторые вспомогательные функции помогут. Я начал работать над решением, и оно «параметризует» «связанный прирост», поэтому гибкость все еще возможна
4. Судя по «предпочел бы такие диапазоны», 1-й диапазон min — это само минимальное значение. А максимальное значение последнего диапазона — это само максимальное значение. 2-й диапазон min и max составляет порядка 1000. Последующие диапазоны составляют порядка 1100. Выполнимо с помощью «арифметической прогрессии» @SpencerD поэтапно
Ответ №1:
Вот подход, который вычисляет минимальный размер шага, необходимый для покрытия диапазона, затем усекает его до ближайшей десятой степени от 10, которая включает размер шага, а затем возвращает точки шага, начиная с min и заканчивая max, с промежуточными границами на расстоянии шага друг от друга, а внешние границы немного выше, чтобы включить размер шага.минимальные / максимальные значения.
const range = (min, max, steps) => {
// minimum step size
stepsize = (max - min) / steps;
// increase the step size to a nice boundary
// for example, 1/10th of the 10^n range that includes it
pow = Math.trunc(Math.log10(stepsize)) - 1;
stepsize = Math.trunc(stepsize / 10 ** pow) * 10 ** pow;
// round min to the same boundary
result = [min];
min = Math.trunc(min / 10 ** pow) * 10 ** pow;
for (let i = 0; i < steps - 1; i ) {
min = stepsize;
result.push(min);
}
result.push(max);
return resu<
}
console.log(range(-1234, 4321, 5));
Ответ №2:
Подход Ника использует формулу «арифметической прогрессии». Это действительно единственный способ решить эту проблему.
Следующее решение учитывает то, что прокомментировал @SpencerD с точки зрения того, как одна арифметическая прогрессия не даст желаемых результатов. Это не прямая последовательность, за исключением «средних» частей с шагом 1100.
Таким образом, я публикую этот ответ, чтобы продемонстрировать, что все еще возможно с арифметической прогрессией, если разбивать ее поэтапно. Оставшееся объяснение содержится в комментариях к коду.
function lowerBound(actualValue, boundIncrement) {
// lets determine the min by an arithmetic progression formula
return Math.floor( actualValue / boundIncrement ) * boundIncrement
}
function upperBound(actualValue, boundIncrement) {
// lets determine the max by an arithmetic progression formula, hence the 1 for the upper range
return (Math.floor( actualValue / boundIncrement ) 1) * boundIncrement
}
function getRanges(min, max) {
let nextMin = min
// now lets use the helper funcs to determine the ranges based on "would prefer ranges like" from question
let ranges = [];
// if 1st range is negative, lets make it that value up to 0
if (min < 0) {
ranges.push([min, 0]);
nextMin = 0;
}
// 2nd range requires special condition that it be on increment of 1,000
if ( max > nextMin) {
// so lets do this without conditions
ranges.push([nextMin, upperBound(nextMin, 1000)]);
nextMin = upperBound(nextMin, 1000);
}
// lets determine if there are subsequent ranges, on increment of 1,100
if (nextMin < max) {
while ( nextMin < max) {
ranges.push([nextMin, upperBound(nextMin, 1100)])
nextMin = upperBound(nextMin, 1100)
}
}
// lastly, lets make (overwrite) the max range's max with the max value instead
ranges[ ranges.length - 1][1] = max
return ranges;
}
function test() {
console.log( getRanges( parseInt(document.getElementById("min").value), parseInt(document.getElementById("max").value) ) );
}
Enter min: <input type="text" id="min" value="-1234">
<br>
Enter max: <input type="text" id="max" value="4321">
<br>
<button onclick="test()">Console.log()</button>