提问人:wcminipgasker2023 提问时间:10/11/2023 最后编辑:wcminipgasker2023 更新时间:10/11/2023 访问量:200
如何将相同的相邻对象分组到一个数组中(例如:[1,1,2,2,2,3,4,4,4] 到 [[1,1],[2,2,2],[3],[4,4,4]])?
How to group same adjacent objects into an array (eg:[1,1,2,2,2,3,4,4,4] to [[1,1],[2,2,2],[3],[4,4,4]])?
问:
例如,我有一个数组:[1,1,2,2,2,3,4,4,4],我想要一个将相同的相邻对象分组到另一个数组中的结果:[[1,1],[2,2,2],[3],[4,4,4]],我该怎么做?我试过了:
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));
我预计是[[1,1],[2,2,2],[3],[4,4,4,4]],但我不知道为什么会是[[1,1],[2,2,2],[3]](错过了最后一组)。
我也试过了
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));
但结果是[[1,1],[2,2,2],[3],[4,4]],在最后一组中错过了“4”。
我该如何解决?
答:
你不是在处理最后一组。你的想法显然是,当你发现一个与前一个元素不同的元素时,推送最后一个组(由从 i、included 到 j、excluded 的所有内容组成)。
但最后一组的追随者与前一组没有不同。
有一些方法可以解决这个问题。例如
const arr=[1,1,2,2,2,3,4,4,4];
const result=[];
for(let i=0,j=1;j<=arr.length;j++){
if(j==arr.length || arr[j-1]!=arr[j]){
result.push(arr.slice(i,j));
i=j;
}
}
document.write(JSON.stringify(result));
基于一个懒惰或的事实。因此,如果是,则不会进行评估。这样可以避免使用越界的索引。即使在 javascript 中,这也不是什么大不了的事情:然后就是 ,这对我们来说是可以的,除非也是,也就是说,除非是内容的可能值。||
j
arr.length
arr[j-1]!=arr[j]
arr[j]
undefined
arr[j-1]
undefined
arr
你也可以简单地,在循环之后,在最后一个之后添加所有的东西(但为此你需要存在于循环之外,所以在循环之前完成)。i
i
let i=0
我不会花太多时间在这上面,我相信你会有很多方法可以完成这项任务。 我主要想指出的是另一种可能性,取自《计算机编程的艺术》,但经常被忽视:哨兵。
由于您的问题是最后一个组没有继任者的特殊情况,因此只需添加一个继任者即可。
const arr=[1,1,2,2,2,3,4,4,4];
const result=[];
arr.push('whateveraslongasitisnot4');
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));
当然,这意味着改变.因此,这并不总是可行的。但是,它避免了每次迭代的测试成本。同样,这也可以通过在组之后处理该特殊情况来避免。所以,我并不是说哨兵是唯一的选择,也不是说它是更快的选择。只是,值得被知道。正如你所看到的,只需一行(添加哨兵)的成本,我就可以保持你的代码不变。arr
j==arr.length
请注意,更简单的解决方案(Marc 在评论中给出的解决方案),即放手 included,是隐式的一个版本:javascript 中的数组在其所有元素之后都有隐式。因此,如果像 my 一样,在数组中找不到,尤其是在末尾,那么,隐式充当哨兵。不确定是不是这么想的,但这是一种看待它的方式。j
arr.length
undefined
whateveraslongasitisnot4
undefined
undefined
Simple One Liner,您可以使用以下代码来获得您期望的结果。
const input = [ 1,1,2,2,2,3,4,4,4,1,1]
const output = input.reduce((acc, curr) => {
(acc.length && acc[acc.length-1][0] === curr)?acc[acc.length-1].push(curr): acc.push([curr])
return acc
}, [])
console.log(output)
您可以使用 reduce
和 Array.prototype.at
来获取结果。
const arr=[1,1,2,2,2,3,4,4,4,];
const result = arr.reduce((acc, curr) => {
const lastArr = acc.at(-1);
if(lastArr?.at(-1) === curr) lastArr.push(curr);
else acc.push([curr]);
return acc;
}, []);
console.log(result);
评论
adjacent
[1,1,2,2,1,1]
const x = [1,1,2,2,2,3,4,4,4]
y = x.reduce((a,c,i) => (c!==x[i-1] && a.push([]), a.at(-1).push(c), a), [])
console.log(y)
如果当前元素与前一个索引中的元素不同,请创建一个新的子数组。
然后,将当前元素推送到最近创建的子数组中。
您必须用数组组逐个检查所有数组。array elements
如果要检查元素是否与元素相同,请遵循以下代码:current
previous
function groupAdjacentElements(arr) {
if (arr.length === 0) {
return [];
}
const result = [];
let currentGroup = [arr[0]];
for (let i = 1; i < arr.length; i++) {
if (arr[i] === arr[i - 1]) {
currentGroup.push(arr[i]);
} else {
result.push(currentGroup);
currentGroup = [arr[i]];
}
}
result.push(currentGroup); // Add the last group
return result;
}
const inputArray = [1, 1, 2, 2, 2, 3, 4, 4, 4];
const groupedArray = groupAdjacentElements(inputArray);
console.log(JSON.stringify(groupedArray));
你可以使用一个可选的链接运算符?.
,并检查最后一个数组是否存在一个值。
const
array = [1, 1, 2, 2, 2, 3, 4, 4, 4],
result = array.reduce((acc, curr) => {
const last = acc.at(-1);
if (last?.[0] === curr) last.push(curr);
else acc.push([curr]);
return acc;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
最快的方法是对数组进行切片,就像在第二个代码段中所做的那样。为了包含最新的项目,我更愿意在循环之后切片最新的块。由于您不需要检查循环中的最新块,因此速度会更快一些。
const arr = [1,1,2,2,2,3,4,4,4];
const result = [];
let prevIdx = 0;
for(let i = 1; i < arr.length; i++){
if(arr[i] !== arr[i-1]){
result.push(arr.slice(prevIdx, prevIdx = i));
}
}
result.push(arr.slice(prevIdx));
document.write(JSON.stringify(result));
` Chrome/117
--------------------------------------------------------------
Alexander slice 1.00x | x10000000 609 641 650 655 677
chrslg slice 1.10x | x10000000 672 688 700 702 728
KooiInc push 2.07x | x1000000 126 130 131 141 144
--------------------------------------------------------------
https://github.com/silentmantra/benchmark `
const arr = [1,1,2,2,2,3,4,4,4];
// @benchmark KooiInc push
arr.reduce((a,c,i) => (c!==arr[i-1] && a.push([]), a.at(-1).push(c), a), [])
// @benchmark chrslg slice
{
const result=[];
for(let i=0,j=1;j<=arr.length;j++){
if(j==arr.length || arr[j-1]!=arr[j]){
result.push(arr.slice(i,j));
i=j;
}
}
result;
}
// @benchmark Alexander slice
const result = [];
let prevIdx = 0;
for(let i = 1; i < arr.length; i++){
if(arr[i] !== arr[i-1]){
result.push(arr.slice(prevIdx, prevIdx = i));
}
}
result.push(arr.slice(prevIdx));
result;
/*@end*/eval(atob('e2xldCBlPWRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3Rvcigic2NyaXB0Iik7aWYoIWUubWF0Y2hlcygiW2JlbmNobWFya10iKSl7bGV0IHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7dC5zcmM9Imh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9naC9zaWxlbnRtYW50cmEvYmVuY2htYXJrL2xvYWRlci5qcyIsdC5kZWZlcj0hMCxkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHQpfX0='));
作为一个衬垫:
const arr = [1, 1, 2, 2, 2, 3, 4, 4, 4, ];
const result = arr.reduce((acc, curr) =>
(acc.at(-1)?.[0] === curr && acc.at(-1).push(curr) || acc.push([curr]), acc),
[]);
console.log(JSON.stringify(result));
评论
j < arr.length
j <= arr.length
arr.slice(i,j)
从“包含索引”到“独占”的切片。因此,在你的第二种方法中,当你这样做时,它会错过最后一个元素i
j
j == arr.length-1
arr.slice(i, j)