# Use map on a different level

I have just started to get used to Mathematica's Map, Apply, and related functions, and I can't figure out how to do maps that require working "one level down".

For example, I am currently trying to take a list of list of things, and basically perform a change of index.

index = {5, 3, 4, 1};
initial = {{1, 3}, {5, 4}, {5, 1}};
(*goal: {{4,2},{1,3},{1,4}}*)


To get the new value, I just have to take the value from initial, and do Position[index, #1].

The problem I have is that

Position[index, #1] & /@ initial


Means that {1,3} is passed as #1, which is not what I want. I could use Flatten to make the first part work, but I don't know how to "undo" the flatten to get back the original groupings.

Is there a way of dealing with these types of "expand list to elements" and the reverse operation when using Map/Apply or am I just trying to use the wrong tool for the job (in which case what is the right tool)?

Alternative phrasing: Is there a way to apply a function to some structure (List, List of List, etc) Mapping a function to all items with a Head different from List so that all the structure is preserved, but the values are changed?

I think this is probably what you were looking for:

Map[Position[index, #][[1, 1]] &, initial, {2}]

{{4, 2}, {1, 3}, {1, 4}}


However you should avoid mapping Position whenever possible as it is highly inefficient. See:

If you are using Mathematica 10 you may use:

asc = First /@ PositionIndex[index]

<|5 -> 1, 3 -> 2, 4 -> 3, 1 -> 4|>

Map[asc, initial, {2}]

{{4, 2}, {1, 3}, {1, 4}}


This may also be done in one line:

Map[First /@ PositionIndex[index], initial, {2}]


Finally, following your Alternative phrasing I believe you want Listable

foo = Function[x, asc @ x, Listable];

foo @ initial

{{4, 2}, {1, 3}, {1, 4}}


Based on the Answer by @MrWizard,

initial /. First /@ PositionIndex[index]


also works.

• Very elegant, though not as generalizeable – soandos Jan 20 '15 at 5:19
• Very clean. +1 :-) – Mr.Wizard Jan 20 '15 at 5:23
• Of course you are correct. The answer by @MrWizard is more general, but more alternatives often is better. Besides, I am learning too. – bbgodfrey Jan 20 '15 at 5:24
• Indeed, more alternatives = better. I was remiss not to mention Replace as it tests faster as I noted in this self-Q&A: (55980). However I was focused on working up to the Listable example as I thought that most fully answered the question, and I forgot about alternatives. – Mr.Wizard Jan 20 '15 at 5:27

First, Position can work directly on more than one value but through Alternatives.

Flatten[Position[index, Alternatives @@ #]] & /@ initial
(*{{2, 4}, {1, 3}, {1, 4}}*)


but as you can see that Position starts with the first position found {2,4} which is not the way you want.

you can use Map to map the Position function on each elements in the list and then use the appropriate Flatten to get your result as follows:

Flatten[Map[Position[index, #] &, initial, {-1}], {1, 3, 4}]
(*{{4, 2}, {1, 3}, {1, 4}}*)


The meaning of that is Map will map the head Position[index, #] & to level {-1} which is the last level of the list which is basically the elements of the list (Check this Level[initial,{-1}]. So for example the first map will be:

Position[index, #] &[1] which will be Position[index, 1] which will be {{4}} and so on for the rest.

Another way is as you said to Flatten everything and then reconstruct the list structure using Partition

Partition[Flatten[Position[index, #] & /@ Flatten[initial]], 2]
(*{{4, 2}, {1, 3}, {1, 4}}*)

• Do you mind explaining Map[Position[index, #] &, initial, {-1}] more? I don't get what the last argument to Map is doing – soandos Jan 20 '15 at 4:53
• @soandos That is the levelspec. Please see my answer and the links within it. – Mr.Wizard Jan 20 '15 at 4:56