Looking for some help in javascript. Heres the problem
Heres my input:
[
{channel: 471, unit: 1},
{channel: 472, unit: 2},
{channel: 473, unit: 3},
{channel: 474, unit: 5},
{channel: 479, unit: 6}
]
And here is what I am looking for as an output:
Ch: 471-474, 479 #1-3,5-6
So essentially looping through an array of objects to summarize numeric values in a sorted manner. I was originally using a math.max()
and math.min()
method to find max and min numbers to display like this:
Ch: 471-479
But that is not accounting for the fact that there is no 475,476,477, or 478.
I was also using an Object.keys() method to turn the objects into arrays to then filter through using math.max
and min
Any idea how I would do something like this? Is it even possible? Any help is appreciated!
for the sake of being thorough, here is my entire code so far where I am stuck
const regex = /Ch (?<channel>\d ): (?<position>(?:\w|\s) ) #(?<units>\d )/g;
const inputString = "Ch 471: PRO BM R #5,Ch 472: PRO BM R #4,Ch 473: PRO BM R #3,Ch 481: PRO BM L #5,Ch 482: PRO BM L #4,Ch 484: PRO BM L #3";
const groups = {};
[...inputString.matchAll(regex)].forEach(a => (groups[a.groups.position] ||= []).push({ channel: a.groups.channel, units: a.groups.units }));
console.log(groups);
const keys = Object.keys(groups);
console.log(keys)
keys.forEach((key,index)=>{
let maxChannelNum = Math.max.apply(Math, groups[key].map(function(x) {return x.channel;}))
let minChannelNum = Math.min.apply(Math, groups[key].map(function(x) {return x.channel;}))
let maxUnitNum = Math.max.apply(Math, groups[key].map(function(x) {return x.units;}))
let minUnitNum = Math.min.apply(Math, groups[key].map(function(x) {return x.units;}))
console.log(`Ch: ${minChannelNum}-${maxChannelNum} ${key} #${minUnitNum}-${maxUnitNum}`)
})
CodePudding user response:
First off, you need to clearly define how exactly you want to display your number ranges and what the minimum interval between each number is - for example, if you're expecting the possibility of floating point numbers (say, 471, 472, 472.5, 473...), you'd have to re-define what counts as part of an interval (for example 471-473) and what breaks an interval (in the aforementioned case that would be a 475).
As long as you can define what counts as part of a range and at what point you need to begin a new one, I don't think there is anything stopping you from the naive approach of simply sorting all of your datasets according to their numerical value; in this case giving you the two sets
471, 472, 473, 474, 479
and
1, 2, 3, 5, 6
and then simply looping through them, selecting the first entry of each data set as the beginning of the range and defining the end of a range once it breaks the condition of your range - in this case, being larger than the preceding number by more than one.
I'm sure there are more optimal ways of achieving this, but does anything speak against this approach outright?
CodePudding user response:
You could take all numbbers, combine continuous numbers and join them to strings.
const
update = (array, value) => {
const
last = array[array.length - 1],
lastValue = last?.[1] || last?.[0];
if (lastValue 1 === value) last[1] = value;
else array.push([value]);
},
input = "Ch 471: PRO BM R #5,Ch 472: PRO BM R #4,Ch 473: PRO BM R #3,Ch 481: PRO BM L #5,Ch 482: PRO BM L #4,Ch 484: PRO BM L #3",
temp = input
.split(',')
.map(s => s.match(/\d /g))
.reduce((r, [a, b]) => {
update(r[0], a);
update(r[1], b);
return r;
}, [[], []])
.map(a => a.map(b => b.join('-')).join()),
result = `Ch: ${temp[0]} #${temp[1]}`
console.log(result);