7

Given some list

numbers = {2,3,5,7,11,13};

How do I translate this to

translatedNumbers = {{1,2},{2,3},{3,5},{4,7},{5,11},{6,13}}

concisely?

I am aware of how to do this using the procedural style of programming as follows:

Module[{lst = {}, numbers = {2, 3, 5, 7, 11, 13}},
  Do[AppendTo[lst, {i, numbers[[i]]}], {i, 1, Length@numbers}]; lst]

But such is fairly verbose for what seems to me to be a simple operation. For example the haskell equivalent of this is

numbers = zip [1..] [2,3,5,7,11,13]

I can't help but think that there is a more concise way of "indexing" a list of numbers in Mathematica.

Potential Answer

Apparently I'm not allowed to answer my own question after having had a lightbulb go off unless I have 100 "rep". So I'll just put my answer here. Let me know if I should do anything differently then I have done.

Well I'm feeling a little silly now after having asked this. For if I treat mathematica lists as a matrix I'm able to transpose them. Thus an answer (perhaps not the best) to my question is as follows:

Transpose[{Range@6, {2, 3, 5, 7, 11, 13}}]

Edited to work for arbitrary input lists, I think something like:

With[{lst={2, 3, 5, 7, 11, 13}},Transpose[{Range@Length@lst,lst}]]

will work. Could I do any better?

nixeagle
  • 1,002
  • 8
  • 17
  • 4
    Your edit looks like the canonical way of doing this. – Sjoerd C. de Vries Dec 09 '11 at 20:07
  • Thanks, as it turns out, I have crossed 100 "rep" recently. Should I now copy my own answer to the question answers and remove from the question body proper? Especially as my answer mirrors (exactly!) two of the answers given. (Also I am holding off selecting an answer as the "answer" to the question in the hopes of more alternatives. In the case that the transpose method is best, which answer should I approve? One of the two given below or mine copied down?) – nixeagle Dec 09 '11 at 21:45
  • 1
    It is tangential to the question being asked, but I would advise to prefer `Module` (or `With`) over `Block` for almost all cases, and use `Block` only if you really know what it does, and why you need it. – Leonid Shifrin Dec 09 '11 at 21:50
  • 2
    Not sure. I've seen it done both ways. People summarizing and wrapping up at the bottom of their question box or as a separate answer. You may want to read the answers to this question: http://meta.stackexchange.com/q/2800/158668 – Sjoerd C. de Vries Dec 09 '11 at 21:54
  • You sure shouldn't accept answers too soon. It will discourage people from trying their own solution. A couple of days is usually fine. – Sjoerd C. de Vries Dec 09 '11 at 22:07
  • @LeonidShifrin If I understand correctly: `Block` is essentially dynamic scoping and `Module` is essentially lexical scoping. One of the references I have read on this is http://reference.wolfram.com/mathematica/tutorial/BlocksComparedWithModules.html. – nixeagle Dec 09 '11 at 22:08
  • @nixeagle Yes, that's true. But dynamic scoping is a special beast. It should not be ordinarily used in places where lexical scoping is appropriate, since it may lead to inadvertent collisions of localized variables (their values), which in turn results in subtle bugs that are very hard to find. In essense, using dynamic scoping in such way is not very much different from re-defining a global variable in many places in a program. You may find this past SO discussion interesting: http://stackoverflow.com/questions/6236458/plot-using-with-versus-plot-using-block-mathematica/6236808#6236808 – Leonid Shifrin Dec 09 '11 at 22:15
  • @LeonidShifrin I will read your link. However it is my impression that dynamic scoping in Mathematica mirrors the implementation of dynamic scoped variables in common lisp. They should(?) have the same behavior? Or is this a case where prior programming assumptions don't apply in *Mathematica*'s pattern matching engine? I'll adjust the question to use `Module` regardless as I don't actually **need** `Block` for here. – nixeagle Dec 09 '11 at 22:23
  • @nixeagle Unfortunately, I don't know CL, so can not comment on dynamic scoping similarities or differences between it and Mathematica. Dynamic scoping in M localizes a *value* of the variable, or, it localizes a variable *in time* rather than in space. Put yet another way, it localizes it not within a place in a program, but within a part of an execution stack. But it is much harder to have a full control over (parts of) the execution stack than it is over parts of the program (lexically scoped). – Leonid Shifrin Dec 09 '11 at 22:32
  • @LeonidShifrin Right, this sounds like `(defvar *var* 2)` in common lisp. One can do `(defun foo () *var*) (list (let ((*var* 3)) (foo)) (foo))` and get a a result `'(3 2)` because `*var*` was modified and placed on the stack within the `let` construct/scope. Mirroring this in MMA one would have `var = 2; foo[] := var; {Block[{var = 3}, foo[]],foo[]}` returning `{3, 2}`. Am I missing something more? – nixeagle Dec 09 '11 at 22:41
  • @nixeagle "Am I missing something more?" Not much here, but in Mathematica `Block` has more powerful uses than just dynamically localize variables, since one can use it also on functions (including built-ins) to make them temporarily forget their global definitions. This can be often used to implement non-trivial evaluation control and other things, and is especially non-trivial for `Block`-ing built-ins, since this is one of the very few ways you can externally alter their behavior. – Leonid Shifrin Dec 09 '11 at 22:48

3 Answers3

7

One thing to consider is if the transformation will not unpack the data. This is important for large data sets.

On["Packing"]

numbers = Developer`ToPackedArray@{2, 3, 5, 7, 11, 13};

This will unpack

MapIndexed[{First[#2], #1} &, numbers]

this will not

Transpose[{Range[Length[#]], #}] &[numbers]

Off["Packing"]
  • My question did not specifically address performance. But now that you have mentioned it: Would `Transpose` be faster than `MapIndexed` even when elements are not packed (or simply unpackable)? – nixeagle Dec 09 '11 at 22:18
  • Is the performance of MapIndexed likely to be improved in the future, or does something unavoidable limit its efficiency? – Mr.Wizard Dec 10 '11 at 05:03
  • @nixeagle I can not answer that in general. You'll have to try it. –  Dec 10 '11 at 09:35
  • @Mr.Wizard in this case MapIndexed will have to unpack which means the evaluator is entering at a whole different level but try to compare it to a compiled version cf = Compile[{{numbers, _Integer, 1}}, MapIndexed[{First[#2], #1} &, numbers]] and see how that performs. –  Dec 10 '11 at 09:55
6

I would use MapIndexed instead

MapIndexed[{First[#2], #1} &, numbers]
cobbal
  • 69,903
  • 20
  • 143
  • 156
1

Well, my „solution“ is perhaps not as smart as the solution from cobbal, but when I test it with long arrays, it is faster (factor of 5!). I am simply using:

newList = Transpose[{Range[Length[numbers]], numbers}]

AHH! ruebenko posted a similar answer during I have written my post. Sorry for this almost superfluous post. Well, perhaps it is not so superfluous. I have tested my solution with and without packing, and it works at fastest without packing.

partial81
  • 495
  • 6
  • 14
  • This is exactly the same as the solution already posted in the edited version of the question which was there two hours before you gave this answer. I'd suggest you remove this answer. – Sjoerd C. de Vries Dec 09 '11 at 21:59
  • Sorry, I did not recognize the edited version of the question after posting this (I just recognized ruebenko’s answer). But since I mentioned the timing problem in my answer as first, I think I should not delete it. If you and other people think it is too superfluous, I do not mind it if will be deleted. Anyway, Nixeagle also asked for a better solution. But so far I only know worse one (Use a for-loop…). Would be interesting to see if there is something that is faster than transpose. – partial81 Dec 09 '11 at 23:34
  • The OP used prefix notation (f@x instead of f[x]) but other than that both solutions are identical. You may want to look at the FullForm of both notations. Identical. – Sjoerd C. de Vries Dec 10 '11 at 09:24