3

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]
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Alex Latro
  • 93
  • 1
  • 10

4 Answers4

2

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]));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Even if it works, it looks like ancient Aramaic text. Code should be immediately understandable especially if it's few lines long. There is no point in sharing solutions like this one in a knowledge sharing platform. This is just entropy. – Yak O'Poe May 12 '20 at 16:32
  • this work not fine. if array = [2,2,2,3] after reduce we get = [2,[2,2],3] First element ignored – Alex Latro May 12 '20 at 19:23
  • @AlexLatro sorry, should work now. the counter was wrong initialized. – Nina Scholz May 12 '20 at 20:25
  • Very cool - hadn't seen `{ [i - 1]: last }` used like that before - handy way to grab previous element – KyleMit Oct 14 '21 at 00:06
1

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]));
Alex Latro
  • 93
  • 1
  • 10
0

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

KyleMit
  • 30,350
  • 66
  • 462
  • 664
-2

Just use Array.reduce() to get that.

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
rupesh raj
  • 17
  • 5