205

I want to use the map() function on a JavaScript array, but I would like it to operate in reverse order.

The reason is, I'm rendering stacked React components in a Meteor project and would like the top-level element to render first while the rest load the images below.

var myArray = ['a', 'b', 'c', 'd', 'e'];
myArray.map(function (el, index, coll) {
    console.log(el + " ")
});

prints out a b c d e, but I wish there was a mapReverse() that printed e d c b a.

How can I do it?

4
  • 4
    Why don't you reverse the array? Commented Apr 5, 2016 at 2:08
  • 2
    To order the elements I set the z-index by the array index. I suppose I could set the z-index to be negative. Commented Apr 5, 2016 at 2:11
  • 1
    On a side note, are you actually using the array that map returns? Otherwise, you ought to consider forEach. Commented Apr 5, 2016 at 2:16
  • 2
    You could access the reverse element within the map callback: console.log(coll[coll.length - index - 1] + " ") Commented May 5, 2017 at 20:49

16 Answers 16

358

If you don't want to reverse the original array, you can make a shallow copy of it then map of the reversed array,

myArray.slice(0).reverse().map(function(...

Update:

myArray.toReversed().map(()=>{...});

The state of JavaScript has advanced since my original answer. Array.toReversed() now has support in most environments, and is a more modern and clean way to express mapping over the original array backwards, without changing the original.

Sign up to request clarification or add additional context in comments.

5 Comments

I ended up just using the negative index to specify the z-index, but in the way I framed the question this is the most correct.
Why do we need .slice(0) ? Why not myArray.reverse() instead of myArray.slice(0).reverse() ? Looks like the answer for my comment is here: stackoverflow.com/questions/5024085/…
Haradzieniec - It goes with the particulars for how the original question was framed, in that the original ordering was needed to set a Z-index css property, but printed in reverse.
@FahdLihidheb reverse() DOES modify the original array.
Sure .reverse() DOES modify its input, but it's almost always possible to do the mapping FIRST, and only then reverse, because .map() creates a fresh array that's not shared anywhere else when reversing: myArray.map(...).reverse() unless the mapping function looks ahead or backwards in the third argument (array) in which case the indexing needs to change
62

Use math on the index provided to the mapping function in order to access elements in reverse order, rather than using the provided val:

myArray.map((val, index) => myArray[myArray.length - 1 - index]);

This is O(n) and does not mutate nor copy the input array.

The third parameter to the mapping function is the underlying collection, so that can also avoid the need to refer to it via a closure:

myArray.map((val, index, array) => array[array.length - 1 - index]);

2 Comments

You could write _val instead of val to denote it's not used. @Paul You need the full syntax (first, second, third) => ... as both the index (second) and the base array/myArray (third) are used here.
Such a great answer, just returned here. Note to myself: [...myArray] or .slice(0) (with or without the 0) make a shallow copy. You could write something like const el = array[array.length - 1 - index] to directly reuse the element like OP does inside his loop in the question.
27

You can use Array.prototype.reduceRight()

var myArray = ["a", "b", "c", "d", "e"];
var res = myArray.reduceRight(function (arr, last, index, coll) {
    console.log(last, index);
    return (arr = arr.concat(last))
}, []);
console.log(res, myArray)

1 Comment

noice (if you are looking to perform a reduce anyways) - MDN: The reduceRight() method applies a function against an accumulator and each value of the array (from right-to-left) to reduce it to a single value.
23

With Named callback function

const items = [1, 2, 3]; 
const reversedItems = items.map(function iterateItems(item) {
  return item; // or any logic you want to perform
}).reverse();

Shorthand (without named callback function) - Arrow Syntax, ES6

const items = [1, 2, 3];
const reversedItems = items.map(item => item).reverse();

Here is the result

enter image description here

3 Comments

map is being used as a shallow copy
This uses items.map as a shallow copy. [...items] or items.slice(0) (with or without the 0) would do the same.
This reverses the results, rather than the order of iteration.
13

Another solution could be:

const reverseArray = (arr) => arr.map((_, idx, arr) => arr[arr.length - 1 - idx ]);

You basically work with the array indexes

3 Comments

This seems like a strange way to go, but the reduceRight approach is also odd if you're wanting access to the index in addition to the element, don't really want to do a reduce, etc. In my case, this was the cleanest solution.
If you need to do further work inside the map, using arr[...] doesn't require a second copy or manipulating the original array. Forgot about the 3rd parameter. What I was looking for!
This is actually duplicated by this higher-voted answer
13

You just need to add .slice(0).reverse() before .map()

students.slice(0).reverse().map(e => e.id)

1 Comment

This uses .slice(0) as a shallow copy. It doesn't matter, with or without the 0. Actually, the last .map makes yet another copy without the need for it.
7

I prefer to write the mapReverse function once, then use it. Also this doesn't need to copy the array.

function mapReverse(array, fn) {
    return array.reduceRight(function (result, el) {
        result.push(fn(el));
        return result;
    }, []);
}

console.log(mapReverse([1, 2, 3], function (i) { return i; }))
// [ 3, 2, 1 ]
console.log(mapReverse([1, 2, 3], function (i) { return i * 2; }))
// [ 6, 4, 2 ]

Comments

3

I think put the reverse() key after map is working.

tbl_products
  .map((products) => (
    <div
      key={products.pro_id}
      class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/4 transform transition duration-500 hover:scale-105"
    >
      <article class="overflow-hidden rounded-lg border shadow">
        <a href="#">
          <img
            alt="Placeholder"
            class="block h-auto w-full px-5 pt-3"
            src={products.product_img}
          />
        </a>
      </article>
    </div>
  ))
  .reverse();

In my case, it is working

Comments

3

You can do myArray.reverse() first.

var myArray = ['a', 'b', 'c', 'd', 'e'];
myArray.reverse().map(function (el, index, coll) {
    console.log(el + " ")
});

3 Comments

That would be my solution in general, but in the setup I'm using the top card is placed with the last index. I guess just some better indexing could solve the problem.
Just as a note, this will reverse the original array in place, meaning it will alter the order of the array destructively.
I started googling after this did not work for me at all. Turns out react in dev mode renders twice, so it was reversing the array twice and ui showed everything in the original order :)
2

Here is my TypeScript solution that is both O(n) and more efficient than the other solutions by preventing a run through the array twice:

function reverseMap<T, O>(arg: T[], fn: (a: T) => O) {
   return arg.map((_, i, arr) => fn(arr[arr.length - i - 1]))
}

In JavaScript:

const reverseMap = (arg, fn) => arg.map((_, i, arr) => fn(arr[arr.length - 1 - i]))

// Or 

function reverseMap(arg, fn) {
    return arg.map((_, i, arr) => fn(arr[arr.length - i - 1]))
}

Comments

2

First, you should make a shallow copy of the array, and then use that function on the copy.

[...myArray].reverse().map(function(...

Comments

1
function mapRevers(reverse) {
    let reversed = reverse.map( (num,index,reverse) => reverse[(reverse.length-1)-index] );
    return reversed;
}

console.log(mapRevers(myArray));

I You pass the array to map Revers and in the function you return the reversed array. In the map cb you simply take the values with the index counting from 10 (length) down to 1 from the passed array

1 Comment

A written explanation as to what this code is doing may be helpful.
1

var myArray = ['a', 'b', 'c', 'd', 'e'];
var reverseArray = myArray.reverse()
reverseArray.map(function (el, index, coll) {
    console.log(el + " ")
});

1 Comment

reverse will also reverse the myArray in-place. As the (unexpected) side effect, your myArray get reversed after executing these codes. The same problem similar to this answer
0

If you are using an immutable array from let's say a redux reducer state, you can apply .reverse() by first making a copy like this:

const reversedArray = [...myArray].reverse();
//where myArray is a state variable

//later in code
reversedArray.map((item, i)=>doStuffWith(item))

Comments

0

Add reverse() into your code snippet:

YourData.reverse().map(...)

Be aware that this will mutate the original array, which can be an issue.

2 Comments

This repeats several answers already. New answers should contain novel solutions, not repeat existing ones.
-2

An old question but for new viewers, this is the best way to reverse array using map

var myArray = ['a', 'b', 'c', 'd', 'e'];
[...myArray].map(() => myArray.pop());

2 Comments

this modifies the original array
maybe you meant: [...myArray].map((_, _, arr) => arr.pop()); ?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.