1

I wonder how I can turn the list $\{a_1,...,a_n\}$ into the new list $\{(a_1,1),...,(a_n,n)\}$, i.e $a_k \mapsto (a_k,k)$, how do I do that?

I figured the function Tuples might work, but it just lists all tuples $(a_i,j)$, $i,j \in [n]$. Can't seem to find any other function that accomplishes what I want. Thanks.

Erik Vesterlund
  • 163
  • 2
  • 8

6 Answers6

4

I've often wondered what the best approach is for this. I find myself combining two lists a and b of the same length in this way quite frequently. I have always used Transpose[{a,b}], but wondered if that was the most efficient way to do it. It seems like it would require moving around a lot of stuff in memory.

So I tested the speed of the solutions shown here, as well as checked whether they preserved packed arrays.

Needs["Developer`"]
a=RandomInteger[1000000000,1000000];
b=Range[1000000];
PackedArrayQ@a
True
PackedArrayQ@b
True
Timing[c=Thread[{a,b}];]
PackedArrayQ@c
{0.278477,Null}
False
Timing[c=Transpose[{a,b}];]
PackedArrayQ@c
{0.011906,Null}
True
Timing[c=MapIndexed[{#1,First@#2}&,a];]
PackedArrayQ@c
{1.256647,Null}
False
Timing[c=MapThread[List,{a,b}];]
PackedArrayQ@c
{0.371252,Null}
False
Timing[c=Inner[List,a,b,List];]
PackedArrayQ@c
{0.274188,Null}
False

I had high hopes for Thread. However Transpose is the clear winner, and the only one that preserves packed arrays.

Any other solutions we should try?

Mark Adler
  • 4,949
  • 1
  • 22
  • 37
3

The most efficient way should be this (because of Transpose):

n = 10;
list = Array[a, n]
Transpose[{ list, Range @ Length[list]}]
{a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10]}
 {{a[1], 1}, {a[2], 2}, {a[3], 3}, {a[4], 4}, {a[5], 5}, 
  {a[6], 6}, {a[7], 7}, {a[8], 8}, {a[9], 9}, {a[10], 10}}

For certain similar functionality look e.g. at Tally, BinLists, BinCounts.

Artes
  • 57,212
  • 12
  • 157
  • 245
2

Here is another option:

n=5;
list=RandomInteger[10,n];
MapIndexed[{#1,First@#2}&,list]

{{10,1},{4,2},{8,3},{2,4},{1,5}}

Murta
  • 26,275
  • 6
  • 76
  • 166
1
n = 5;

list = Array[a, n];

Thread[{list, Range[Length[list]]}]

{{a[1], 1}, {a[2], 2}, {a[3], 3}, {a[4], 4}, {a[5], 5}}

EDIT (addressing additional question in OP comment): If m and n are known:

m = 10; n = 6;

list = Array[a, n];

Thread[{list, Range[m - n + 1, m]}]

{{a[1], 5}, {a[2], 6}, {a[3], 7}, {a[4], 8}, {a[5], 9}, {a[6], 10}}

Bob Hanlon
  • 157,611
  • 7
  • 77
  • 198
1

There are a lot of ways to accomplish this, one of them is also MapIndexed:

list = RandomInteger[{1, 20}, 10]

and then

MapIndexed[{#1, First @ #2} &, list]
mgamer
  • 5,593
  • 18
  • 26
0

This will do what you want:

Module[{i = 1},
 {#, i++} & /@ RandomReal[{-1, 1}, 10]
]

You need to localise the i iterator so that it works on multiple occasions. If you didn't do this, the second column would start at whatever the length of the previous list was.

It should be noted that this method performs similarly to, but a bit more slowly than, the MapIndexed solution proposed by others.

list = RandomReal[{-1, 1}, 1000000];

Module[{i = 1}, {#, i++} & /@ list]; // Timing

(*{0.967206, Null}*)

MapIndexed[{#1, First@#2} &, list]; // Timing

(*{0.904806, Null} *)
Verbeia
  • 34,233
  • 9
  • 109
  • 224
c186282
  • 1,402
  • 9
  • 17