javascript 如何将相同的相邻对象分组到数组中(例如:[1,1,2,2,2,3,4,4,4]到[[1,1],[2,2,2],[3],[4,4,4]])?

brccelvz  于 2023-10-14  发布在  Java
关注(0)|答案(8)|浏览(113)

例如,我有一个数组:[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));

“我不知道,我也不知道。
我也试

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”。
我该怎么修复它?

eufgjt7s

eufgjt7s1#

你不是在和最后一组打交道。你的想法显然是当你发现一个与前一个元素不同的元素时,推送最后一个组(由从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));

基于||是一个惰性或的事实。所以如果jarr.length,那么arr[j-1]!=arr[j]就不会被计算。这避免了使用索引越界。即使如此,在JavaScript中,这也不是什么大不了的事情:那么arr[j]将只是undefined,这对我们来说是可以的,除非arr[j-1]也是,也就是说,除非undefinedarr内容的可能值。
你也可以简单地在循环之后,在最后一个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的成本。同样,这也是可以避免的,通过在群体之后处理特殊情况。所以,我并不是说哨兵是唯一的选择,也不是说它是更快的一个。只是,值得被人知道。正如您所看到的,只需要一行代码(添加sentinel),我就可以保持您的代码不变。
请注意,更简单的解决方案(Marc在注解中给出的解决方案),即只让j包含arr.length,这是隐含的版本:JavaScript中的数组在所有元素后都有隐式的undefined。所以,如果像我的whateveraslongasitisnot4undefined在数组中找不到,特别是在最后,那么,隐式的undefined就像一个哨兵。我不确定是不是这么想的,但这是一种看待它的方式。

brgchamk

brgchamk2#

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

vs91vp4v3#

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)

如果当前元素与前一个索引中的元素不同,则创建一个新的子数组。
然后,将当前元素推入最近创建的子数组。

0s7z1bwu

0s7z1bwu4#

你必须检查所有的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));
zi8p0yeb

zi8p0yeb5#

你可以取一个optional chaining operator ?.并检查最后一个数组是否存在值。

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

23c0lvtd6#

最快的方法是像在第二个代码片段中那样对数组进行切片。为了包含最新的项,我更喜欢在循环后切片最新的块。因为你不需要在循环中检查最新的块,所以它会更快一点。

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

fhg3lkii7#

作为一个班轮:

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

ctehm74n8#

你可以使用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);

相关问题