Reputation: 18905
Is there an Array method that can replace the following function (Something like a.splice(some, tricky, arguments)
)?
function resize(arr, newSize, defaultValue) {
if (newSize > arr.length)
while(newSize > arr.length)
arr.push(defaultValue);
else
arr.length = newSize;
}
If not, is there a better / nicer / shorter / implementation? The function should append a default value if the array should grow and remove values on shrink.
Upvotes: 17
Views: 52370
Reputation: 1
Suggestion:
const expectedLength = 500;
myArray = myArray.filter((element, index) => {
if (index < expectedLength) {
return element;
}
});
Upvotes: 0
Reputation: 481
It is much more efficient to resize an array once, than it is to do a large number of .push
es. This can be accomplished by the setter feature on Array.prototype.length
:
function resize(arr, newLength, defaultValue) {
const oldLength = arr.length;
arr.length = newLength;
if (newLength > oldLength && typeof(defaultValue) !== 'undefined') {
for (let i = oldLength; i < newLength; i++) {
arr[i] = defaultValue;
// Note: this will create many references to the same object, which
// may not be what you want. See other answers to this question for
// ways to prevent this.
}
}
}
Upvotes: 1
Reputation: 192006
This solution will only work for new browsers (except IE) due to Array.prototype.fill (see Browser compatibility at the bottom of the linked page) or using a polyfill.
function resize(arr, newSize, defaultValue) {
var originLength = arr.length; // cache original length
arr.length = newSize; // resize array to newSize
(newSize > originLength) && arr.fill(defaultValue, originLength); // Use Array.prototype.fill to insert defaultValue from originLength to the new length
}
Upvotes: 2
Reputation: 4670
In terms of elegance, I would say you could trim down your original solution to:
function resize(arr, newSize, defaultValue) {
while(newSize > arr.length)
arr.push(defaultValue);
arr.length = newSize;
}
Or use prototype:
Array.prototype.resize = function(newSize, defaultValue) {
while(newSize > this.length)
this.push(defaultValue);
this.length = newSize;
}
Edit: ES2016 approach:
function resize(arr, newSize, defaultValue) {
return [ ...arr, ...Array(Math.max(newSize - arr.length, 0)).fill(defaultValue)];
}
Upvotes: 23
Reputation: 3919
You can use the following code for resizing arrays:
// resizing function for arrays
Array.prototype.resize = function( newSize, defaultValue )
{
while( newSize > this.length )
{
typeof( defaultValue ) === "object" ? this.push( Object.create( defaultValue ) ) : this.push( defaultValue );
}
this.length = newSize;
}
I checked the type of defaultValue
because if it is an object and you just push it to the new elements, you will end up with an array which new elements point to the same object. That means if you change a property of that object in one of your array's element, all others will also change. But if your defaultValue
is a primitive, you can safely push it to the new elements.
Upvotes: 2
Reputation: 14809
If you are one-liner-lover like me,
what you're asking would be what my resize_array_right
does.
const resize_array_left = (array, length, fill_with) => (new Array(length)).fill(fill_with).concat(array).slice(-length);
// Pads left when expanding an array.
// Put left elements first to be removed when shrinking an array.
const resize_array_right = (array, length, fill_with) => array.concat((new Array(length)).fill(fill_with)).slice(0, length);
// Pads right when expanding an array.
// Put right elements first to be removed when shrinking an array.
You can find it out in NPM, as resize-array
.
Upvotes: 3
Reputation: 17023
Expanding on James solution:
Array.prototype.resize = function(newSize, defaultValue) {
while(newSize > this.length)
this.push(defaultValue);
this.length = newSize;
}
If you want to get even more efficient, you could do browser detection for Array.prototype.fill
and use that instead of the while loop.
if (Array.prototype.fill) {
Array.prototype.resize = function (size, defaultValue) {
var len = this.length;
this.length = size;
if (this.length - len > 0)
this.fill(defaultValue, len);
};
} else {
Array.prototype.resize = function (size, defaultValue) {
while (size > this.length)
this.push(defaultValue);
this.length = size;
};
}
If someone has included a polyfill for Array.prototype.fill
, then you want them to use your non-fill version instead. A polyfill would cause the fill method to be slower than the non-fill version.
This StackOverflow Q&A deals with how to detect if a function is natively implemented. You could work that into the initial condition, but that is just additional speed lost.
I'd probably only use this solution if you could ensure that no Array.prototype.fill
would exist.
Upvotes: 1
Reputation: 9415
function resize(arr, size, defval) {
while (arr.length > size) { arr.pop(); }
while (arr.length < size) { arr.push(defval); }
}
I think this would be more efficient though:
function resize(arr, size, defval) {
var delta = arr.length - size;
while (delta-- > 0) { arr.pop(); }
while (delta++ < 0) { arr.push(defval); }
}
And while not as elegant, this would probably me the most efficient:
function resize(arr, size, defval) {
var delta = arr.length - size;
if (delta > 0) {
arr.length = size;
}
else {
while (delta++ < 0) { arr.push(defval); }
}
}
Upvotes: 7