'Javascript: Replace same consecutive elements of an array into one item that shows their count in

I have an array like this :

const array = [1, 3, x, x, 4, x, x, x, 9, x, x, x, x, 7]

I want to turn all consecutive elements which has the value of x into one element that shows their count between numbers such as :

const newArray = [1, 3, '2x', 4, '3x', 9, '4x', 7]

For instance, 3 consecutive x in the array like [x, x, x] should be turned into one ['3x'] while numbers should stay untouched.



Solution 1:[1]

Maybe there's a better solution for achieving that. Of course, there's! But here is a solution by using the for loop. Check every iteration if the element is x, increase the x value by 1. And if the current element is not x, then reset the x variable to 0.

Sample Result:

const array = [1, 3, 'x', 'x', 4, 'x', 'x', 'x', 9, 'x', 'x', 'x', 'x', 7];

let x = 0;
let result = [];

for (let i = 0; i < array.length; i++) {
  if (array[i] === 'x') {
    x++;
    if (array[i + 1] === 'x') continue;
    result.push(`${x}x`);
    continue;
  }
  x = 0;
  result.push(array[i]);
}

console.log(result);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration

Solution 2:[2]

const array = [1, 3, 'x', 'x', 4, 'x', 'x', 'x', 9, 'x', 'x', 'x', 'x', 7]

const newArray = array.map(item => `${item}`).reduce((acc, curr)=>{
    if(curr !== 'x') return [...acc, curr];
    
    const previous = acc.pop();
    if(!previous || !previous.includes('x')) return [...acc, previous, '1x'];

    const xCounter = 1 + parseInt(previous.match(/\d+/)[0]);
    return [...acc, `${xCounter}x`];
    
},[])

console.log(newArray)

Solution 3:[3]

The simplest way is just to iterate all elements:

// Your array
const array = [
  1,
  3,
  "x",
  "x",
  4,
  "x",
  "x",
  "x",
  9,
  "x",
  "x",
  "x",
  "x",
  7
];

// Create new array
const newArr = [];

// Set internal value repeat counter
let cn = 1;

// Iterate array
for(let i = 0; i < array.length; i++) {
  // Set trigger
  let trig = 1;
  
  // If next param exist and it is equals current
  if(array[i+1] && array[i+1] === array[i]) {
    // Increase counter
    cn++;
    // Set trigger to false
    trig = 0;
  }
  
  // If trigger is true
  if(trig) {
    // If internal counter greater then 1
    // push previous value and its counter
    if(cn > 1) {
      newArr.push(`${cn}${array[i-1]}`);
      // Reset counter
      cn = 1;
    }
    
    // Else just push current value
    else newArr.push(array[i]);
  }
}

// Test
console.log(newArr);

And then you can try to shrink the code with something more advanced:

// Your array
const arr = [1,3,"x","x",4,"x","x","x",9,"x","x","x","x",7];

// Use flatMap
let cn = 1;
const res = arr.flatMap((e, i, a) => {
  return a[i+1] && a[i+1] == e ? (cn++) && [] :
  cn > 1 ? (()=>{const t = cn; cn = 1; return t+''+a[i-1]})() : e;
});

// Result
console.log(res);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 EEAH
Solution 3