How to reduce JS array length if next elements equal previous

Viewed 533

I'd like to combine identical elements in an array, into a single term with how many times the value appears

function combineArrayElements(arr) {
  return arr.map((e, i, ar) => {
    if (e === ar[i + 1] || (e[0] && e[0] === ar[i + 1])) {
      return [e, e[1] + 1]
    }
    return e;
  })
}

Some example input and output:

// input  [3, 2, 2, 5, 1, 1, 7, 1]
// output [3,[2,2],5,[1,2],7,1]

// input  [1, 1, 1, 2, 1]
// output [[1,3], 2, 1]
4 Answers

You could reduce the array and if the value is equal the last value, take an array and increment the counter.

const
    getGrouped = array => array.reduce((r, v, i, { [i - 1]: last }) => {
        if (v === last) {
            if (!Array.isArray(r[r.length - 1])) r[r.length - 1] = [r[r.length - 1], 1];
            r[r.length - 1][1]++;
        } else {
            r.push(v);
        }
        return r;
    }, []);

console.log(getGrouped([3, 2, 2, 5, 1, 1, 1, 7, 1]));
console.log(getGrouped([2, 2, 2, 3]));

Thank, Joseph Cho - answer is:

function splitCounts(arr) {
  let res = [];
  let count = 1;

  for (let i=0; i<arr.length; i++) {
    if (arr[i] === arr[i+1]) {
      count++;
    } else {
      res.push([arr[i], count]);
      count = 1;
    }
  }

  return res;
}

// [[3,1],[2,2],[5,1],[1,2],[7,1],[1,1]]
console.log(splitCounts([3,2,2,5,1,1,7,1]));

Refactored Nina Scholz's answer with longer variable names, comments, and slightly different control of flow:

const combineAdjacentElements = array => array.reduce((acc, val, i) => {
    // if cur is different from prev value, add raw number
    if (val !== array[i - 1]) {
      acc.push(val)
      return acc
    }

    // if first repetition, replace val with grouped array
    if (typeof acc.at(-1) === 'number') {
        acc[acc.length - 1] = [val, 2];
        return acc
    }

    // if multiple repetition, increment counter in grouped array
    acc.at(-1)[1]++;
    return acc;
}, []);


const output = combineAdjacentElements([3, 2, 2, 2, 5, 1, 1, 7, 1])

console.log(JSON.stringify(output, null, 0))
// [3,[2,3],5,[1,2],7,1]

Further Reading

Just use Array.reduce() to get that.

Related