I have an array containing numbers, in that array there're some numbers that occur many times in consecutive order one after the other, and I want to compress those repeated numbers into a very specific format 'Number*Times' to reduce the size of the array:
input: [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0]
---------^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^--------
output: [0, 1, 2,'0x3', 3, 2, '0x6', 5, 6, 0]
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0];
let string = array.toString();
let string_compressed = string.replace(/(\d ,)(\1) /g, (x) => {
return "Number*" x.split(",").length ",";
});
let array_compressed = string_compressed
.split(",")
.map((x) => (isNaN(Number(x)) ? x : Number(x)));
console.log(array_compressed); //[0, 1, 2, 'Number*4', 3, 2, 'Number*7', 5, 6, 0]
I don't know how to get the number that repeated so I put Number instead!
I used regex to solve it, I know if you think to solve problem with regex, they become two problems!
BUT Guys I'm sure this isn't the efficient way to solve this problem, And there're other ways to solve it!
what do you suggest if you want to solve this problem?
CodePudding user response:
Because your regex to find how many numbers repeat already only matches numbers that are in consecutive order in your array, you can simply just take the first index of the x.split(",")
array and return that.
Edit:
Also, as @qrsngky out, your x.split(",").length
wasn't actually the right length, because when you split it by comma, there is a null character at the end:
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0];
let string = array.toString();
let string_compressed = string.replace(/(\d ,)(\1) /g, (x) => {
console.log(x.split(","));
return "Number*" x.split(",").length ",";
});
let array_compressed = string_compressed
.split(",")
.map((x) => (isNaN(Number(x)) ? x : Number(x)));
console.log(array_compressed);
Sorry for missing that, and props to the comments! I just fixed it by subtracting one from the length.
Edit 2:
For edge cases, we can just add a comma and use slice.
I attached the complete fixed code snippet below:
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0];
let string = array.toString() ",";
let string_compressed = string.replace(/(\d ,)(\1) /g, (x) => {
return x.split(",")[0] "*" (x.split(",").length - 1) ",";
});
let array_compressed = string_compressed
.slice(0, -1)
.split(",")
.map((x) => (isNaN(Number(x)) ? x : Number(x)));
console.log(array_compressed);
CodePudding user response:
Assume your original array consists of none other than numbers.
Non-regex approach: based on a for loop and counting how many repetitions had been encountered.
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0]
let buffer = [];
let currentNum = array[0], count = 1;
for (let i = 1; i < array.length; i ) {
if (array[i] === currentNum) {
count;
} else {
buffer.push( count === 1 ? currentNum : (currentNum 'x' count) );
currentNum = array[i];
count = 1;
}
}
//don't forget the last number
if(currentNum !== undefined) buffer.push( count === 1 ? currentNum : (currentNum 'x' count) );
console.log(buffer);
The if(currentNum !== undefined)
check is only useful in case it's an empty array.
CodePudding user response:
Another example of how not to do it with string manipulation by coding what you want done:
function packArray(array) {
var packed = [];
for( var i = 0; i < array.length; i=j) {
var entry = array[i];
for(var j = i 1; array[j] === entry && j<array.length; j);
packed.push( j > i 1 ? `${entry}x${j-i}` : entry);
}
return packed;
}
console.log( packArray([0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0]))
You could substitute let
for var
except for var j
which should remain the same to allow access to j
outside the nested for
loop.