For example, I have an array : [1,1,2,2,2,3,4,4,4], I want a result that group the same adjacent objects into another array : [[1,1],[2,2,2],[3],[4,4,4]], how can I do that? I tried:
const arr=[1,1,2,2,2,3,4,4,4];
const result=[];
for(let i=0,j=1;j<arr.length;j++){
if(arr[j-1]!=arr[j]){
result.push(arr.slice(i,j));
i=j;
}
}
document.write(JSON.stringify(result));
Which I expect [[1,1],[2,2,2],[3],[4,4,4,4]] but I don’t know why would it be [[1,1],[2,2,2],[3]] (missed the last group).
I also tried
const arr=[1,1,2,2,2,3,4,4,4];
const result=[];
for(let i=0,j=1;j<arr.length;j++){
if(arr[j-1]!=arr[j] || j==arr.length-1){
result.push(arr.slice(i,j));
i=j;
}
}
document.write(JSON.stringify(result));
but the result is [[1,1],[2,2,2],[3],[4,4]], which missed a "4" at the last group.
How do I fix it?
4
Answers
You are not dealing with the last group. Your idea is obviously to push the last group (made of everything from i, included to j, excluded) when you find an element that is different from the previous.
But the last group has no follower different from the previous.
There are ways to solve that. For example
Based on the fact that
||
is a lazy or. So ifj
isarr.length
thenarr[j-1]!=arr[j]
would not be evaluated — which is fortunate, since that would be an index out of bound. Which, in javascript, is not a big deal:arr[j]
would then just be undefined. Which is ok for us. Unlessarr[j-1]
also is, that is unlessundefined
is a possible value ofarr
content.You could also simply, after the loop, add every thing after the last
i
(but for that you needi
to exist outside the loop).But I also want to point out another possibility, taken from "The Art of Computer Programming", and often overlook: a sentinel.
Since your problem is the particular case of last group having no successor, just add a successor.
Sure, that means altering
arr
. So it is not always feasible. But then it avoid the cost of testingj==arr.length
at every iteration. Again, that is also avoidable by treating that special case after the group. So, I am not claiming sentinel is the only option, nor that it is the faster one. Just, that it worth to be known. As you can see, to the cost of just one line (adding the sentinel) I can keep your code as is.Note that the simpler solution (the one given in comments by Marc), that is just letting
j
go toarr.length
included, is implicitly a version of that: arrays in javascript have implicitundefined
after all their elements. So, if, as mywhateveraslongasitisnot4
,undefined
is not to be found in array, and especially not at the end, then, that implicitundefined
acts as a sentinel. Not sure it was thought that way, but that is a way of seeing it.You can use the below code to get the result that you are expecting.
You can use
reduce
andArray.prototype.at
to get the result.Maps can be useful in this case.