I have an array of prices
I would like to group these prices into ranges if they are within 2 of each other
How do I achieve this
// present array
const array = [
'3','5','6','12','17','22'
]
// the result I want
const array_ranges = [
'3-6', '12',
'17','22'
]
CodePudding user response:
Here is the longer script - at least it is more readable.
const array = ['3', '5', '6', '12', '14', '17', '22'];
const arrRange = array.reduce((acc, num, i) => {
if (i === 0) {
acc.push(num);
return acc;
}
let range = acc[acc.length - 1].split("-");
const last = range[range.length - 1];
if ((num - last)<=2) {
if (range.length === 1) range.push(num)
else range[range.length - 1] = num;
acc[acc.length - 1] = range.join("-")
} else acc.push(num);
return acc;
}, []);
console.log(arrRange)
CodePudding user response:
You could define an offset of 2
and check the last pair if the delta is greater as this offset and push a new value the result set, otherwise take the value of the first part of the last stored or value and build a new pair.
const
array = ['3','5','6','12','17','22'],
offset = 2,
result = array.reduce((r, v, i, a) => {
if (!i || v - a[i - 1] > offset) r.push(v);
else r.push(`${r.pop().split('-', 1)[0]}-${v}`);
return r;
}, []);
console.log(result);
CodePudding user response:
One possible generic, configurable and re-usable approach was to implement the reducer function as function statement where the initial value is an object of two properties threshold
and result
where the former defines a range value's tolerance or delta to its previous/next range value and the latter featuring all created/collected range values.
The reducer does process an array of just number values; therefore a map
task which assures number values only has to be executed before.
function createAndCollectNumberRanges({ threshold, result }, current, idx, arr) {
threshold = Math.abs(threshold);
const previous = arr[idx - 1] ?? null;
const next = arr[idx 1] ?? null;
if (
previous === null ||
previous < current - threshold
) {
result.push(String(current));
} else if (
(next > current threshold || next === null) &&
previous >= current - threshold
) {
result.push(`${ result.pop() }-${ current }`);
}
return { threshold, result };
}
console.log(
['3', '5', '6', '12', '17', '22']
.map(Number)
.reduce(createAndCollectNumberRanges, {
threshold: 2,
result: [],
}).result
);
console.log(
['0', '3', '5', '6', '12', '14', '15', '17', '22', '23']
.map(Number)
.reduce(createAndCollectNumberRanges, {
threshold: 2,
result: [],
}).result
);