14
$\begingroup$

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$
6
  • 2
    $\begingroup$ why not just list1[[{1, 2}]] = list1[[{2, 1}]]; list1 $\endgroup$
    – kglr
    Sep 25, 2014 at 10:06
  • 1
    $\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, 2014 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, 2014 at 10:30
  • $\begingroup$ Please see specifically: (18737) $\endgroup$
    – Mr.Wizard
    Sep 25, 2014 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, 2014 at 19:52

2 Answers 2

17
$\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$
8
  • $\begingroup$ Just to make it more clear: the last temp in the function is (almost) the same as Return[temp] $\endgroup$ Sep 25, 2014 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, 2014 at 10:32
  • 1
    $\begingroup$ @rcollyer I just stiched to your jacket the golden sportman's badge :) $\endgroup$
    – eldo
    Sep 25, 2014 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, 2014 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, 2014 at 12:07
6
$\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$
1
  • $\begingroup$ According to what OP wanted, I think the first output should be ${3,2,1,4}$. Am I wrong? :) $\endgroup$ Mar 19, 2016 at 15:23

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