Home > Enterprise >  JavaScript arrays: how do I compact excess length?
JavaScript arrays: how do I compact excess length?

Time:05-01

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."


PS: to those people who show hostility to this critical questions and downvote and move to close, you have not provided an answer, nor do you allege the truth about this question. You have no basis to move to close at all. The question is as clear and detailed and focused as it needs to be. And the hostility towards this question simply reflects the fact that I am putting my finger into a dirty wound. If you think you are so smart then provide a complete and true definition of the semantics of the Array length property, and don't lie about my question to suit your desire to shut it down.

CodePudding user response:

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

  • Related