8
$\begingroup$

This question already has an answer here:

Ok, this will probably be a silly question, but I can't get my head around it. I'm making a simple module that, given a list and two integers, will swap the position of the elements in the list.(probably there's a function that does it, but I'm interested in doing it myself) This is what I have so far:

Exchange[list_, i_, j_] := Module[{temp},
  temp = list[[i]];
  list[[i]] = list[[j]];
  list[[j]] = temp;
  Return[list];
  ]

Then I do: list1 = {1, 2, 3, 4} And finally:

Exchange[list1, 1, 2]

But it returns this error: Set::setps: "{1,2,3,4} in the part assignment is not a symbol." And the list is unchanged. I looked at the help but I don't understand how I'm supposed to make a valid assignment. I know that what is wrong are the lines 2 and 3 of the module... Any help is greatly appreciated

$\endgroup$

marked as duplicate by Mr.Wizard Sep 25 '14 at 14:24

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    $\begingroup$ why not just list1[[{1, 2}]] = list1[[{2, 1}]]; list1 $\endgroup$ – kglr Sep 25 '14 at 10:06
  • $\begingroup$ I suppose there are ways to do this without making a module, but I'm learning mathematica and my purpose is not really to exchange the elements, but to learn how to make modules, and I can't understand why my code doesn't work. $\endgroup$ – Erdorath Sep 25 '14 at 10:16
  • $\begingroup$ @erdorath Could you make clear whether your goal is to change the content of the original variable list1? Because then, non of the answer will help you (except the first block of kgugler which doesn't use a Module). $\endgroup$ – halirutan Sep 25 '14 at 10:30
  • $\begingroup$ Please see specifically: (18737) $\endgroup$ – Mr.Wizard Sep 25 '14 at 14:24
  • $\begingroup$ @Mr.Wizard sorry, didn't see that answer when i searched for the error. In any case all of the answers were very constructive to me. $\endgroup$ – Erdorath Sep 25 '14 at 19:52
11
$\begingroup$

The problem here is that in Mathematica, parameters of a function are not local variables. So trying to modify a parameter of a function inside it's body will lead to an error. The reason is that function arguments are evaluated, when the function is called so that it is actually the result of this evaluation that's textually substituted for the function parameters within the body. To fix this (without using advanced techniques), assign that parameter to a local variable and work with that variable inside the body of the function. Here's a simple fix to your function:

exchange[list_, i_, j_] := Module[{temp}, 
  temp = list; 
  temp[[i]] = list[[j]]; 
  temp[[j]] = list[[i]];
  temp
]

Now:

exchange[list1, 1, 2]

{2, 1, 3, 4}

Note that I've removed Return in your definition as it's not needed here. Also note that the original list remains intact and is not changed.

$\endgroup$
  • $\begingroup$ Just to make it more clear: the last temp in the function is (almost) the same as Return[temp] $\endgroup$ – Dr. belisarius Sep 25 '14 at 10:29
  • $\begingroup$ Thank you! this is pretty much what I wanted to know. (as I suppose you will have figured I'm more used to functional and OO programming languages, so this is a bit confusing for me) $\endgroup$ – Erdorath Sep 25 '14 at 10:32
  • 1
    $\begingroup$ @rcollyer I just stiched to your jacket the golden sportman's badge :) $\endgroup$ – eldo Sep 25 '14 at 21:04
  • 1
    $\begingroup$ @RunnyKine Speaking of "reputation" I'd like to know what happened in mid July: stackexchange.com/users/2317480/runnykine?tab=reputation -- that's an amazing jump in activity! :-) I hope you didn't entirely replace water with Red Bull in your diet. :^) $\endgroup$ – Mr.Wizard Sep 26 '14 at 11:45
  • 2
    $\begingroup$ @Mr.Wizard. Long Story. Before July, I did most of my research in different languages ( Mostly C# ). So I only posted here occasionally, plus I was still new to Mathematica (really started using it when I joined this site last year). After the release of V10, the mesh functions made my life easier so I decided to use M for the remainder of my program and I realized I've been wasting my time (but that's another story). Finally, I replaced water with Redbull + Gin :) $\endgroup$ – RunnyKine Sep 26 '14 at 12:07
4
$\begingroup$

If you want to change the original list "directly" (inplace) you can do it with HoldFirst:

SetAttributes[Exchange, HoldFirst];

Exchange[list_, a_, b_] := list[[{a, b}]] = list[[{b, a}]]

list1 = {1, 2, 3, 4};

Exchange[list1, 3, 1];

list1

{3, 1, 2, 4}

Multiple swaps:

list1 = {1, 2, 3, 4};

Exchange[list1, ##] & @@@ {{4, 1}, {2, 3}} // Flatten;

list1

{4, 3, 2, 1}

$\endgroup$
  • $\begingroup$ According to what OP wanted, I think the first output should be ${3,2,1,4}$. Am I wrong? :) $\endgroup$ – H. R. Mar 19 '16 at 15:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.