'JavaScript arrays: how do I compact excess length?
This might look like a duplicate question, but please don't assume this just because it looks similar to others, and be careful with easy answers unless you really understand the ramifications.
Here is a console dialog to demonstrate the problem:
> a = [0,1,2]
< >(3) [0,1,2]
> a.length
< 3
> a[99] = 99
< 99
> a.length
< 100
> delete a[99]
< true
> a.length
< 99
So this length property of arrays doesn't seem to follow any reasonable specification. Trailing sparse elements should be compacted out, but aren't.
I think as a result, the length property should never be used in code since it is semantically meaningless. (Instead findLastIndex(() => true) should be used anywhere a naive programmer woul previously use length.)
I know how to use the elegant forEach, some, every, find, filter, map, and reduce functions. And I know that filter doesn't preserve sparseness. I can use reduce to do a map which can drop elements or a filter which preserves sparseness.
How can we reset the array length property to something reasonable without copying the array?
There may be no answer at all, or rather, the answer may be "there is no way and the array length property is essentially meaningless."
Solution 1:[1]
Since nothing in JavaScript specification says length must be exactly one higher than the last index, your demand is not reasonable. In common use, dense arrays overwhelmingly outnumber sparse ones. Since JavaScript does not keep indices in an ordered structure, finding out which index is the last every time array contents change would incur a performance toll in a number of cases where this stronger invariant is not needed.
If you actually need to trim down an array to exclude the trailing non-elements, it is easy enough to do: find the last valid index, and shrink the array yourself:
const a = [0,1,2]
a[99] = 99
delete a[99]
a.length = a.findLastIndex(i => i in a) + 1;
console.log(a); // [1, 2, 3]
console.log(a.length); // 3
Can it be slow, in case where length is large? Yes. This is precisely why this calculation is not done by default.
EDIT: findLastIndex is not present in all browsers, a workaround or a polyfill might be required.
EDIT2: Better yet, reduce can be employed, which does not call the predicate for the absent indices (and is also present in all current browsers):
const a = [0,1,2]
a[99] = 99
delete a[99]
a.length = a.reduce((l, x, i) => i, 0) + 1;
console.log(a); // [1, 2, 3]
console.log(a.length); // 3
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 |
