skip to Main Content

Basically what title says: I want to be able to call .map on a reversed array, but I’m afraid that it would be too slow since I have to do this operation numerous times.

I know that the following method works:

let arr  = [1, 2, 3, 4, 5];
let rev_wrapped = arr.slice(0).reverse().map(item => `wrapped: ${item}`);

where rev_wrapped turns out to be:

[
  'wrapped: 5',
  'wrapped: 4',
  'wrapped: 3',
  'wrapped: 2',
  'wrapped: 1'
]

I was wondering if there is any faster way to do this, since .reverse() reverses the array entirely, while I just need to read data in reverse order.

In case this isn’t possible, I would also be ok with a data structure which allows me to insert elements at the start without too much computational cost (since something like arr.splice(0,0,new_item) would rearrange the array completely at every insertions).

3

Answers


  1. You can use this simple helper function (or inline its implementation wherever you want to use it, if needed for chaining purposes).

    function reversedMap(arr, mapper) {
      const { length } = arr;
      return arr.map((_, i) => mapper(arr[length - 1 - i]));
    }
    
    let arr  = [1, 2, 3, 4, 5];
    
    console.log(reversedMap(arr, item => `wrapped: ${item}`));
    Login or Signup to reply.
  2. Your current code makes three passes through the array (slice, to make the copy; reverse, to reverse it; and map to map it). If performance is a concern and you have found that your current approach is too slow (I suggest measuring, not speculating), you’re probably best off just using a simple loop:

    let arr  = [1, 2, 3, 4, 5];
    let rev_wrapped = new Array(arr.length);
    for (let i = 0, n = arr.length - 1; n >= 0; --n, ++i) {
        rev_wrapped[i] = `wrapped: ${arr[n]}`;
    }
    console.log(rev_wrapped);

    Normally, new Array is an anti-pattern, but in modern JavaScript engines new Array(5) will typically pre-allocate storage (something I learned recently and was surprised by).

    Alternatively, you could use the map callback in Array.from:

    let arr  = [1, 2, 3, 4, 5];
    let rev_wrapped = Array.from(arr, (_, index) => {
        const item = arr[arr.length - index - 1];
        return `wrapped: ${item}`;
    });
    console.log(rev_wrapped);

    In each case, you’re just making one pass through the array.

    Login or Signup to reply.
  3. I think the fastest approach is by using Array.prototype.reduceRight:

    const arr  = [1, 2, 3, 4, 5],
          result = arr.reduceRight((a, item) => ([...a, `wrapped: ${item}`]), []);
    
    console.log(result);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search