Swap two variables without using a temporary variable

190,535

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.

Share:
190,535
Sreedhar
Author by

Sreedhar

:-)

Updated on September 12, 2021

Comments

  • Sreedhar
    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
    Tjkoopa about 15 years
    Most 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
    Nils Pipenbrinck about 15 years
    True, 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
    Kennet Belenky about 15 years
    That'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
    patjbs about 15 years
    As long as you don't run into overflow issues, that works just fine
  • Willem Van Onsem
    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
    Willem Van Onsem about 15 years
    little 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
    Dirk Vollmar about 15 years
    What 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
    Willem Van Onsem about 15 years
    and 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
    paxdiablo about 15 years
    The 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
    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
    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
    Willem Van Onsem about 15 years
    of course this is the best way, but it was explicit asked without temp variable
  • Nelson Reis
    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
    Doug McClean almost 15 years
    What'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
    helpermethod over 13 years
    I hope the XOR swap will be forgotten one day.
  • Gabriel Magana
    Gabriel Magana over 13 years
    XOR swap is near the pinnacle of nerdiness. I had nirvana for a couple days after learning it in school.
  • Willem Van Onsem
    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
    koumides almost 12 years
    Maybe 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
    Pramod over 11 years
    Even 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
    Mike over 11 years
    This technique is more computationally expensive than using a temporary variable.
  • Willem Van Onsem
    Willem Van Onsem over 11 years
    Yes 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
    Marcus about 11 years
    Yes, but only in the method, not where you do the switch.
  • AsherMaximum
    AsherMaximum almost 11 years
    If memory is in short supply, such as on an embedded device, then temp variables are in short supply sometimes.
  • Andrew Savinykh
    Andrew Savinykh almost 11 years
    This does not seem to work at all stackoverflow.com/questions/5577140/…
  • paxdiablo
    paxdiablo almost 11 years
    AFAIK, 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
    Olivier Jacot-Descombes over 10 years
    Using 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
    Olivier Jacot-Descombes over 10 years
    Simple, 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
    Sebastian over 10 years
    @OlivierJacot-Descombes, I hope if you call it a million times, the JIT will optimize it.
  • Mike de Klerk
    Mike de Klerk over 9 years
    At least add a comment so it is also understandable for the non-"binary ninja's"
  • tbone
    tbone over 9 years
    It'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
    Kevin S over 9 years
    I 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
    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
    Willem Van Onsem about 9 years
    @tbone: in Python you virtually create some kind of tuple. That's the third value.
  • Willem Van Onsem
    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
    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
    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
    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
    Jeppe Stig Nielsen about 9 years
    This is C#. The above code does not swap, as @zespri says. To your last sentence: In C# you cannot use the operator ^= with string or float, so it will not compile with them.
  • Willem Van Onsem
    Willem Van Onsem almost 9 years
    Bit 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
    jnm2 almost 9 years
    You'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
    Mark Ransom almost 9 years
    So 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-
    rr- almost 9 years
    I believe this to be the pinnacle of nedriness. Guy assembles a working program in Pokemon by swapping items in inventory.
  • Chris Beck
    Chris Beck over 8 years
    If 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
    Isochronous over 8 years
    Pretty sure that z counts as a temp variable here.
  • Bo Persson
    Bo Persson almost 8 years
    This is exactly the same as several of the other answers. Some of which were added already 7 years ago!
  • Peter Mortensen
    Peter Mortensen over 7 years
    How is ECMAscript relevant? The question is tagged C#.
  • Clearer
    Clearer about 6 years
    proper c++: std::swap(x, y);.
  • artman
    artman over 5 years
    @Isochronous if you move it out of function and make static It wont be temp anymore lol
  • Jeffrey Vest
    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
    Jeffrey Vest about 5 years
    It'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
    paxdiablo about 5 years
    Jeffrey, 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
    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
    Syroot over 4 years
    How performant is this though? I always fear some "Tuple" instance created on the heap internally and all those fancy things happening.
  • prime23
    prime23 over 4 years
  • TheBeardedQuack
    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
    AlexWei about 4 years
    @TheBeardedQuack Your link show correct results. Why you say it does not work with primitive types?
  • TheBeardedQuack
    TheBeardedQuack about 4 years
    No it doens't... It shoes a and b both equal to 10 after instead of a successful swap.
  • jmistx
    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
    TheBeardedQuack about 4 years
    I 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
    Richard Keene almost 4 years
    I'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
    Raj Rao over 3 years
    This code works in .net 5.0. And when I viewed the IL, it actually implements the swap, with an additional variable.
  • ABPerson
    ABPerson about 3 years
    Oh dear god what is that :P
  • HGMamaci
    HGMamaci about 3 years
    @ABPerson - Any comments to take serious?
  • ABPerson
    ABPerson about 3 years
    Huh? What do you mean?
  • Mass Dot Net
    Mass Dot Net about 3 years
    Runs fine in Roslyn 3.8: dotnetfiddle.net/Hgblyd
  • AlanK
    AlanK almost 3 years
    1. In C# this does not work, see stackoverflow.com/q/13540480/1848953. 2. In all C-like languages it breaks when a and b contain an equal value because x ^ x == 0 (you lose the value in a and b). 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?