GOAL: add all elements from an array of integers and arrays, each child array is a set of 2 integers denoting a start and end of a range.
HTML invocation:
<div class="block" onclick="test([33,88,[1,5],[8,13],[22,25]]);">click</div>
<div id="paper"></div>
I have the following JavaScript:
<script>
function test(clickArray) {
let theArray = [];
for (i = 0; i < clickArray.length; i++) {
theArray.push(clickArray[i]);
if (clickArray[i].length > 1) {
range(clickArray[i][0], clickArray[i][1], theArray);
}
}
writeArray(theArray);
}
function writeArray(anArray) {
let pencilArray = [];
for (let i = 0; i < anArray.length; i++) {
pencilArray.push();
}
document.getElementById("paper").innerHTML = pencilArray.join("<br>");
}
function range(start, end, rangeArray) {
for (let i = start; i <= end; i++) {
rangeArray.push(i);
}
return rangeArray;
}
</script>
When I invoke the onclick JavaScript the output is:
33
88
1,5
1
2
3
4
5
8,13
8
9
10
11
12
13
22,25
22
23
24
25
Both the range passed and the elements constructed by the range() function are added to the final array, but I just want the elements, not the ranges, so output should be:
33
88
1
2
3
4
5
8
9
10
11
12
13
22
23
24
25
It is generally not a good idea to use inline event handlers. Here's a snippet using Event Delegation, and a one line reducer (test) to create the ranges from a string containing range values (two values or a single range)
document.addEventListener(`click`, handle);
// reducer here
const test = array => array.reduce( (acc, [s, e]) =>
acc.concat( [...Array(e + 1 - s)].map( (v, i) => i + s) ), [] );
function handle(evt) {
if (evt.target.dataset.ranges) {
// make sure a range contains two values. This allows single numbers
const createRawRange = val => val.length < 2 ? [val, val] : val;
// create ranges array from dataset, convert strings to Number
const ranges = evt.target.dataset.ranges.split(";")
.reduce( (acc, val) =>
[...acc, createRawRange(val.split(`,`)).map(Number)], [] );
// apply reducer (test) and print
document.querySelector(`pre`).textContent = JSON.stringify(test(ranges));
}
}
Add ranges <button data-ranges="88;1,5;8,13;22,25;33;43,47">
<!-- ^ single value -->
88; 1-5; 8-13; 22-25; 33; 43-47
</button>
<pre></pre>
Here's how you can handle numbers along with ranges.
const test = (arr) => {
const allNumbers = arr.reduce((acc, el) => {
if (Array.isArray(el)) {
const [start, end] = el;
for (let i = start; i <= end; i++) {
acc.push(i)
}
} else if (!Number.isNaN(el)) {
acc.push(el)
}
return acc
}, [])
document.getElementById('paper').innerHTML = allNumbers.join('<br />');
}
<div class="block" onclick="test([[1,5],[8,13],[22,25], 99]);">click</div>
<div id="paper"></div>