Swap two variables without using a temporary variable
Solution 1
First of all, swapping without a temporary variable in a language as C# is a very bad idea.
But for the sake of answer, you can use this code:
startAngle = startAngle + stopAngle;
stopAngle = startAngle - stopAngle;
startAngle = startAngle - stopAngle;
Problems can however occur with rounding off if the two numbers differ largely. This is due to the nature of floating point numbers.
If you want to hide the temporary variable, you can use a utility method:
public static class Foo {
public static void Swap<T> (ref T lhs, ref T rhs) {
T temp = lhs;
lhs = rhs;
rhs = temp;
}
}
Solution 2
C# 7 introduced tuples which enables swapping two variables without a temporary one:
int a = 10;
int b = 2;
(a, b) = (b, a);
This assigns b
to a
and a
to b
.
Solution 3
The right way to swap two variables (at the time this question was asked(1)) is:
decimal tempDecimal = startAngle;
startAngle = stopAngle;
stopAngle = tempDecimal;
In other words, use a temporary variable.
There you have it. No clever tricks, no maintainers of your code cursing you for decades to come, no entries to The Daily WTF, and no spending too much time trying to figure out why you needed it in one operation anyway since, at the lowest level, even the most complicated language feature is a series of simple operations.
Just a very simple, readable, easy to understand, t = a; a = b; b = t;
solution.
In my opinion, developers who try to use tricks to, for example, "swap variables without using a temp" or "Duff's device" are just trying to show how clever they are (and failing miserably).
I liken them to those who read highbrow books solely for the purpose of seeming more interesting at parties (as opposed to expanding your horizons).
Solutions where you add and subtract, or the XOR-based ones, are less readable and most likely slower than a simple "temp variable" solution (arithmetic/boolean-ops instead of plain moves at an assembly level).
Do yourself, and others, a service by writing good quality readable code.
That's my rant. Thanks for listening :-)
As an aside, I'm quite aware this doesn't answer your specific question (and I'll apologise for that) but there's plenty of precedent on SO where people have asked how to do something and the correct answer is "Don't do it".
(1) Improvements to the language and/or .NET Core since that time have adopted the "Pythonic" way using tuples. Now you can just do:
(startAngle, stopAngle) = (stopAngle, startAngle);
to swap values.
Solution 4
Yes, use this code:
stopAngle = Convert.ToDecimal(159.9);
startAngle = Convert.ToDecimal(355.87);
The problem is harder for arbitrary values. :-)
Solution 5
int a = 4, b = 6;
a ^= b ^= a ^= b;
Works for all types including strings and floats.
Comments
-
Sreedhar over 2 years
I'd like to be able to swap two variables without the use of a temporary variable in C#. Can this be done?
decimal startAngle = Convert.ToDecimal(159.9); decimal stopAngle = Convert.ToDecimal(355.87); // Swap each: // startAngle becomes: 355.87 // stopAngle becomes: 159.9
-
Tjkoopa about 15 yearsMost types that the XOR thing works for would fit in a register so the compiler shouldn't allocate stack space for it anyway.
-
Nils Pipenbrinck about 15 yearsTrue, but it's more complex than that. You rarely need to swap values on a assembler level. The swapping can often be done as a side-effect of other arithmetic. Most of the time the swap is just required to express things in a high level language. After compiling the swap is no more and thus costs no time at all :-)
-
Kennet Belenky about 15 yearsThat's fine for integers or fixed-point numbers. With floating point numbers you'll end up with minute rounding errors. They may or may not be big enough to matter, depends on how you're using the numbers.
-
patjbs about 15 yearsAs long as you don't run into overflow issues, that works just fine
-
Willem Van Onsem about 15 years@Kennet Belenky: indeed, but i don't see another work around, except a temporary value. So I think it's the only "good" way to solve this problem. (Sorry for my English, if I made mistakes)
-
Willem Van Onsem about 15 yearslittle bit equal to my solution, but notice that multiplications and division operation cost a lot of CPU-time. And the upper- and lower-bounds of a float are more easy to reach with multiplication.
-
Dirk Vollmar about 15 yearsWhat do you mean with "Decimal doesn't allow for decimal places"? That sounds confusing as the decimal type does represent real numbers with a high precision (decimal d = 9.1m; is perfectly valid in C#).
-
Willem Van Onsem about 15 yearsand what if one of the variables is zero (or both), the second division will cause an error (division by zero). And the function created could better return false to warn the user, that the swap operation wasn't completed.
-
paxdiablo about 15 yearsThe only good way to solve this problem is to use a temp variable. "Clever" code like this (and, by "clever", I mean "stupid") is far less readable and obvious than the temp-variable solution. If I saw code like this from one of my minions, they'd be subject to sanctions and sent back to do it right. I'm not having a go at you specifically, @CommuSoft (since you answered the question), but the question itself was rubbish.
-
BenAlabaster about 15 years@divo: I stand corrected... I must've missed that class, I'd been trying to assign Decimal n = 9.1; and it just gives me a compiler error. Missed the M on the end :P Answer modified accordingly.
-
Marc Gravell about 15 years+1; and for more reasons: with the +/- (etc) tricks you are doing unnecessary arithmetic. With integers, that may be just about acceptable at a push (the rounding/overflow aren't issues, and the CPU cost is virtually nil), but with decimals, add and subtract are non-trivial operations. It can't even use the FPU, as they aren't float/double. So use a temp variable already!!!
-
Willem Van Onsem about 15 yearsof course this is the best way, but it was explicit asked without temp variable
-
Nelson Reis about 15 years+1 I agree with you. When you start complicating simple stuff you end up with all sort of problems to solve in the next few years...
-
Doug McClean almost 15 yearsWhat's up with your swap method? Why does it return a bool, why is that bool always true (if it exists)? Why does it swallow all exceptions (which could only be a ThreadAbortException in this case, I believe, since it doesn't allocate memory or enlarge the call stack)?
-
helpermethod over 13 yearsI hope the XOR swap will be forgotten one day.
-
Gabriel Magana over 13 yearsXOR swap is near the pinnacle of nerdiness. I had nirvana for a couple days after learning it in school.
-
Willem Van Onsem over 12 years@Janusz Lenar: Well in languages with pointer manipulation you could use the same trick to swap the pointers. In C# you can do this in an unsafe environment. :D But anyway I admit swapping objects,ect. without a third variable is a bad idea (in reaction to this. __curious_geek). But the question said explicitly to do it without an extra variable.
-
koumides almost 12 yearsMaybe there is a genuine reason for not using the temp variable. If the two variables are extremely big, you wouldn't want to create a new one hence having 3 extremely big in variables even not for long time.
-
Pramod over 11 yearsEven on c, if pointers are involved (e.g in function) *a ^= *b ^= *a ^= *b does not work (local variable however works e.g c ^= d ^= c ^= d), but *a ^= *b ^= *a; *b ^= *a; works. My choice thus would be to use *a ^= *b; *b ^= *a; *a ^= *b; which works perfectly.
-
Mike over 11 yearsThis technique is more computationally expensive than using a temporary variable.
-
Willem Van Onsem over 11 yearsYes I know, but again, the question asked if it was possible to do it without a temporary variable. If you compile the code with a temporary variable, it probably won't even require additional memory since the temporary variable would only be stored in a register of the processor. But I suppose the question was homework or something equivalent.
-
Marcus about 11 yearsYes, but only in the method, not where you do the switch.
-
AsherMaximum almost 11 yearsIf memory is in short supply, such as on an embedded device, then temp variables are in short supply sometimes.
-
Andrew Savinykh almost 11 yearsThis does not seem to work at all stackoverflow.com/questions/5577140/…
-
paxdiablo almost 11 yearsAFAIK, the problem it solved was how to unroll a loop in C, allowing for a non-integer multiplier on the first or last cycle. You can do that just as easily without reverting to Duff's Device, and in a much more readable way. If you think it solved a different problem that can't be solved more "readably", I'm open to being convinced. In any case, even if it solved a problem at some point in the past, it's almost never necessary nowadays, even on all but the puniest embedded systems.
-
Olivier Jacot-Descombes over 10 yearsUsing an abstraction is a good way of solving the problem. It provides a general solution to a common problem and makes the calling code easier to read. Of course it uses a few extra bytes of memory and a few extra processor cycles, but unless you are calling this code millions of times, you won't notice any difference.
-
Olivier Jacot-Descombes over 10 yearsSimple, strongly typed assignements not involving array variance will never throw exceptions. Type mismatches will be caught at compile time (this is what strong typing is about).
-
Sebastian over 10 years@OlivierJacot-Descombes, I hope if you call it a million times, the JIT will optimize it.
-
Mike de Klerk over 9 yearsAt least add a comment so it is also understandable for the non-"binary ninja's"
-
tbone over 9 yearsIt's worth adding that the right way in C# is to use a temp variable, but that's doesn't make it a universal fact. The idiomatic way in Python would be a, b = b ,a
-
Kevin S over 9 yearsI don't like the sentence "swapping without a temp variable is a very bad idea". Many languages support swapping variables in a clear way without the mistake-prone 3-line shuffle, so it's logical to ask if C# does. Python:
a, b = b, a
, C++:std::swap(a, b)
. -
Willem Van Onsem over 9 years@KevinS: Sure, some CPU's even have specific instructions or a macro for it. But using mathematical tricks to process it is not how it is supposed to be done. It is error-prone, is hard to understand. And for Python, what you do is create a tuple as a third variable. For
C++'s
swap you simply hide the third value in the method (or it is processed by the CPU directly). In case it is however not available, not using such variable is asking for trouble. -
Willem Van Onsem about 9 years@tbone: in Python you virtually create some kind of tuple. That's the third value.
-
Willem Van Onsem about 9 years@AsherMaximum: but it would be better if C# offered a way to swap two variables. Then this can be implemented with or without temp variable. By doing it explicitly, the code becomes unreadable and is hard to maintain.
-
tbone about 9 years@CommuSoft temporary objects are not the same as temporary variables. right or wrong, that extra temp pollutes readability whereas the pythonic way is squeaky clean.
-
Willem Van Onsem about 9 years@tbone: well actually a temporary variable never exists. It requires liveness analysis to determine when a variable is alive and that is the stage of the compiler where one takes temporary objects into account. At syntax level, a variables starts living at declaration and dies at the end of the method. There are only local and global variables...
-
tbone about 9 years@CommuSoft "Temporary variable" is not a language construct, there's no need for twisting words. This is about terseness and readability, not about compiler output or VM behaviour.
-
Jeppe Stig Nielsen about 9 yearsThis is C#. The above code does not swap, as @zespri says. To your last sentence: In C# you cannot use the operator
^=
withstring
orfloat
, so it will not compile with them. -
Willem Van Onsem almost 9 yearsBit hacks are actually not slow at all. For instance in order to load
0
into a register, a compiler will xor the variable with itself because the instruction is shorter. In some rare occasions by using less variables, one avoids register spilling. It is the compilers job, but it is unfortunate that there is no language support to do this efficiently. -
jnm2 almost 9 yearsYou're right. In cases where this is a hotspot and speed matters that badly, you are going to need to go unmanaged. Bit hacks often backfire in managed languages. That's really the responsibility of the jitter.
-
Mark Ransom almost 9 yearsSo the question is, why wasn't this handy function included in the .NET library? It's the first example given in the documentation for Generic Methods.
-
rr- almost 9 yearsI believe this to be the pinnacle of nedriness. Guy assembles a working program in Pokemon by swapping items in inventory.
-
Chris Beck over 8 yearsIf I ever fly in a US govt. manufactured fighter jet, or have to have a pacemaker, etc., I seriously hope that I don't die because of a stackoverflow caused by some programmer who "hoped that XOR swap would be forgotten some day"
-
Isochronous over 8 yearsPretty sure that
z
counts as a temp variable here. -
Bo Persson almost 8 yearsThis is exactly the same as several of the other answers. Some of which were added already 7 years ago!
-
Peter Mortensen over 7 yearsHow is ECMAscript relevant? The question is tagged C#.
-
Clearer about 6 yearsproper c++:
std::swap(x, y);
. -
artman over 5 years@Isochronous if you move it out of function and make static It wont be temp anymore lol
-
Jeffrey Vest about 5 years"Don't do it" responses are one of the viruses of SO. The response assumes context and is not productive. The method of making a temporary variable is much less readable than tuple based approaches that allow a simple single line obvious and readable swap that is better and cleaner in every way than these temp variable approaches. Had he asked a bit later when that feature existed in C# maybe he would've gotten that productive answer rather than these useless rants that exist just to make the person stating them feel superior.
-
Jeffrey Vest about 5 yearsIt's just a shame this feature didn't exist previously, where he would've potentially learned a powerful new language construct that would've given him more tools in his toolbox to crack problems open with, instead of all the useless rants above.
-
paxdiablo about 5 yearsJeffrey, every answer to a question assumes some context, that's unavoidable. But "don't do it" answers are sometimes the best ones. If you use an unsorted variable record length text file as a multi-gigabyte database, you should be told it's a bad idea. And, before you start assigning motives to people, you may want to at least consider the possibility that some people do know more than others on certain subjects. I know I consider that to be so since I've asked questions here as well on areas I'm deficient in. That is, after all, what makes sites like this useful. ...
-
paxdiablo about 5 years... I'll quite happily admit that Python's tuple assignment is by far the more readable way but C# didn't have that when the answer was posted. In any case, that readability does not carry over to the xor or add/sub methods - they are far less readable than a temp-var solution.
-
Syroot over 4 yearsHow performant is this though? I always fear some "Tuple" instance created on the heap internally and all those fancy things happening.
-
prime23 over 4 years
-
TheBeardedQuack about 4 years-1, I just tested this approach on IDEone and it does not work with primitive types, unlikely it'll work with reference type data either. ideone.com/03zt9U
-
AlexWei about 4 years@TheBeardedQuack Your link show correct results. Why you say it does not work with primitive types?
-
TheBeardedQuack about 4 yearsNo it doens't... It shoes
a
andb
both equal to 10 after instead of a successful swap. -
jmistx about 4 years@TheBeardedQuack that is because the site you are using is using the
gcms
compiler which targets mscorlib2.0 (.NET Framework 2.0, not .Net core) You need to use a more recent compiler -
TheBeardedQuack about 4 yearsI did try this on my local PC too using .NET Framework 4.7 and it didn't work. Also the question has no tags or mention of specifically targetting .NET Core. Either way, it's not a universal solution so millage may vary, and perhaps it should not be recommended so highly.
-
Richard Keene almost 4 yearsI'm not sure why the negative comment from paxdiablo. This solution is a very Functional and compact solution. And the method says what it does. So what is the problem with it??? Correction: A more functional approach now with Tuples is to do an inline swap. THAT is "the functional way". (a, b) = (b, a);
-
Raj Rao over 3 yearsThis code works in .net 5.0. And when I viewed the IL, it actually implements the swap, with an additional variable.
-
ABPerson about 3 yearsOh dear god what is that :P
-
HGMamaci about 3 years@ABPerson - Any comments to take serious?
-
ABPerson about 3 yearsHuh? What do you mean?
-
Mass Dot Net about 3 yearsRuns fine in Roslyn 3.8: dotnetfiddle.net/Hgblyd
-
AlanK almost 3 years1. In C# this does not work, see stackoverflow.com/q/13540480/1848953. 2. In all C-like languages it breaks when
a
andb
contain an equal value becausex ^ x == 0
(you lose the value ina
andb
). It is cool nerdy stuff to show a newbie programmer but why do people show the trick without teaching why it should never be used?