如何将相同的相邻对象分组到一个数组中(例如:[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]])?

提问人: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]],我该怎么做?我试过了:

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”。

我该如何解决?

JavaScript 数组 for 循环

评论

6赞 Marc 10/11/2023
更改为 .j < arr.lengthj <= arr.length
0赞 derpirscher 10/11/2023
arr.slice(i,j)从“包含索引”到“独占”的切片。因此,在你的第二种方法中,当你这样做时,它会错过最后一个元素ijj == arr.length-1arr.slice(i, j)

答:

4赞 chrslg 10/11/2023 #1

你不是在处理最后一组。你的想法显然是,当你发现一个与前一个元素不同的元素时,推送最后一个组(由从 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 中,这也不是什么大不了的事情:然后就是 ,这对我们来说是可以的,除非也是,也就是说,除非是内容的可能值。||jarr.lengtharr[j-1]!=arr[j]arr[j]undefinedarr[j-1]undefinedarr

你也可以简单地,在循环之后,在最后一个之后添加所有的东西(但为此你需要存在于循环之外,所以在循环之前完成)。iilet 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));

当然,这意味着改变.因此,这并不总是可行的。但是,它避免了每次迭代的测试成本。同样,这也可以通过在组之后处理该特殊情况来避免。所以,我并不是说哨兵是唯一的选择,也不是说它是更快的选择。只是,值得被知道。正如你所看到的,只需一行(添加哨兵)的成本,我就可以保持你的代码不变。arrj==arr.length

请注意,更简单的解决方案(Marc 在评论中给出的解决方案),即放手 included,是隐式的一个版本:javascript 中的数组在其所有元素之后都有隐式。因此,如果像 my 一样,在数组中找不到,尤其是在末尾,那么,隐式充当哨兵。不确定是不是这么想的,但这是一种看待它的方式。jarr.lengthundefinedwhateveraslongasitisnot4undefinedundefined

2赞 Deepak Goyal 10/11/2023 #2

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)

0赞 DecPK 10/11/2023 #3

您可以使用 reduceArray.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);

评论

0赞 Alexander Nenashev 10/11/2023
它不是相邻的值,而是对相同的值进行分组
0赞 DecPK 10/11/2023
@AlexanderNenashev 根据预期结果。用户希望对值进行分组。我想要一个将相同的相邻对象分组到另一个数组中的结果:[[1,1],[2,2,2],[3],[4,4,4]]
1赞 Alexander Nenashev 10/11/2023
关键是.OP 不希望所有值分组,应该给出 3 个数组adjacent[1,1,2,2,1,1]
1赞 Andrew Parks 10/11/2023 #4

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)

如果当前元素与前一个索引中的元素不同,请创建一个新的子数组。

然后,将当前元素推送到最近创建的子数组中。

1赞 Mohit Nandpal 10/11/2023 #5

您必须用数组组逐个检查所有数组。array elements

如果要检查元素是否与元素相同,请遵循以下代码:currentprevious

    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));

1赞 Nina Scholz 10/11/2023 #6

你可以使用一个可选的链接运算符?.,并检查最后一个数组是否存在一个值。

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; }

1赞 Alexander Nenashev 10/11/2023 #7

最快的方法是对数组进行切片,就像在第二个代码段中所做的那样。为了包含最新的项目,我更愿意在循环之后切片最新的块。由于您不需要检查循环中的最新块,因此速度会更快一些。

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='));

0赞 KooiInc 10/11/2023 #8

作为一个衬垫:

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));