138

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
4
  • 1
    decimal stopAngle = Convert.ToDecimal(159.9); decimal startAngle = Convert.ToDecimal(355.87); Commented Oct 10, 2017 at 9:49
  • Never convert a floating point to a decimal. It should be string, not a floating point, e.g. Convert.ToDecimal("159.9") Commented Oct 18, 2020 at 19:05
  • 1
    Technically, no. You can only make your code appear as though it does, but underneath, there must always be a third variable: Here is why, All variables are a declarion of type: (Number of bit's the type can hold) and value (The actual value of said type) if you have a memory block, with something like a 4 bit type -> 1000 (1 in decimal) (Variable A) and another memory block with something like a 4 bit type -> 0100 (2 in decimal) (Variable B) When you want to store A in B, the value of b will be overwritten by A. There is no way for you to retain the value of B. Commented Sep 11, 2021 at 15:51
  • 1
    The ONLY way to retain the value of B, in my previous text, is to store B, in some other value. (Temporary or not) until such a time that the previous Value of B (saved in the third variable memory block) has been stored in A. Then you can free up the third values memory for something else, and you are back to, two variables, but swapping values MUST be done this way. Then someone will say "What if it done by reference and not value?" It's the same problem, the reference to A and the reference to B, must be held, while one reference points to, two values, otherwise, you can't reconnect. Commented Sep 11, 2021 at 15:54

30 Answers 30

319

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.

Sign up to request clarification or add additional context in comments.

11 Comments

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.
How performant is this though? I always fear some "Tuple" instance created on the heap internally and all those fancy things happening.
@TheBeardedQuack Your link show correct results. Why you say it does not work with primitive types?
This code works in .net 5.0. And when I viewed the IL, it actually implements the swap, with an additional variable.
|
248

The right way to swap two variables, at the time this question was asked (1), is to use a temporary variable:

decimal tempDecimal = startAngle;
startAngle = stopAngle;
stopAngle = tempDecimal;

There you have it. No clever tricks, no maintainers of your code cursing you for decades to come, 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, temp = a; a = b; b = temp; 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 "temporary 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. This almost won't change the underlying operations but it at least has the small advantage of not having to introduce a temporary named variable to your code. And, in fact, you can see it still using a temporary variable (by pushing/popping values to/from the stack) under the covers, with an (a, b) = (b, a) statement:

IL_0005: ldloc.1  ; push b
IL_0006: ldloc.0  ; push a
IL_0007: stloc.2  ; t = pop (a)
IL_0008: stloc.0  ; a = pop (b)
IL_0009: ldloc.2  ; push t
IL_000a: stloc.1  ; b = pop (t)

I would hope that that code has not yet been through an optimiser, since it appears to me that it could be done without a temporary t (location 2) even at the IL level, since the stack is effectively the temporary. In other words, something like:

IL_0005: ldloc.1  ; push b
IL_0006: ldloc.0  ; push a
IL_0007: stloc.1  ; b = pop (a)
IL_0008: stloc.0  ; a = pop (b)

16 Comments

+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!!!
of course this is the best way, but it was explicit asked without temp variable
+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...
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.
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. ...
|
140

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;
    }
}

12 Comments

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.
As long as you don't run into overflow issues, that works just fine
@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.
This technique is more computationally expensive than using a temporary variable.
Not really. add / sub of integers are cheap compared to additional memory operations.
No additional memory operations required. For this simple operation the temporary variable will likely be kept in a CPU register, which is extremely fast.
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).
|
76

Yes, use this code:

stopAngle = Convert.ToDecimal(159.9);
startAngle = Convert.ToDecimal(355.87);

The problem is harder for arbitrary values. :-)

Comments

41
int a = 4, b = 6;
a ^= b ^= a ^= b;

Works for all types including strings and floats.

10 Comments

I hope the XOR swap will be forgotten one day.
XOR swap is near the pinnacle of nerdiness. I had nirvana for a couple days after learning it in school.
This does not seem to work at all stackoverflow.com/questions/5577140/…
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.
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"
|
27

BenAlabaster showed a practical way of doing a variable switch, but the try-catch clause is not needed. This code is enough.

static void Swap<T>(ref T x, ref T y)
{
     T t = y;
     y = x;
     x = t;
}

The usage is the same as he shown:

float startAngle = 159.9F
float stopAngle = 355.87F
Swap(ref startAngle, ref stopAngle);

You could also use an extension method:

static class SwapExtension
{
    public static T Swap<T>(this T x, ref T y)
    {
        T t = y;
        y = x;
        return t;
    }
}

Use it like this:

float startAngle = 159.9F;
float stopAngle = 355.87F;
startAngle = startAngle.Swap(ref stopAngle);

Both ways uses a temporary variable in the method, but you don't need the temporary variable where you do the swapping.

4 Comments

Yes, but only in the method, not where you do the switch.
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.
@OlivierJacot-Descombes, I hope if you call it a million times, the JIT will optimize it.
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.
18

In C# 7:

(startAngle, stopAngle) = (stopAngle, startAngle);

Comments

17

A binary XOR swap with a detailed example:

XOR truth table:

a b a^b
0 0  0
0 1  1
1 0  1
1 1  0

Input:

a = 4;
b = 6;

Step 1: a = a ^ b

a  : 0100
b  : 0110
a^b: 0010 = 2 = a

Step 2: b = a ^ b

a  : 0010
b  : 0110
a^b: 0100 = 4 = b

Step 3: a = a ^ b

a  : 0010
b  : 0100
a^b: 0110 = 6 = a

Output:

a = 6;
b = 4;

Comments

15

Not in C#. In native code you might be able to use the triple-XOR swap trick, but not in a high level type-safe language. (Anyway, I've heard that the XOR trick actually ends up being slower than using a temporary variable in many common CPU architectures.)

You should just use a temporary variable. There's no reason you can't use one; it's not like there's a limited supply.

4 Comments

Most types that the XOR thing works for would fit in a register so the compiler shouldn't allocate stack space for it anyway.
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 :-)
If memory is in short supply, such as on an embedded device, then temp variables are in short supply sometimes.
@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.
14

For the sake of future learners, and humanity, I submit this correction to the currently selected answer.

If you want to avoid using temp variables, there are only two sensible options that take first performance and then readability into consideration.

  • Use a temp variable in a generic Swap method. (Absolute best performance, next to inline temp variable)
  • Use Interlocked.Exchange. (5.9 times slower on my machine, but this is your only option if multiple threads will be swapping these variables simultaneously.)

Things you should never do:

  • Never use floating point arithmetic. (slow, rounding and overflow errors, hard to understand)
  • Never use non-primitive arithmetic. (slow, overflow errors, hard to understand) Decimal is not a CPU primitive and results in far more code than you realize.
  • Never use arithmetic period. Or bit hacks. (slow, hard to understand) That's the compiler's job. It can optimize for many different platforms.

Because everyone loves hard numbers, here's a program that compares your options. Run it in release mode from outside Visual Studio so that Swap is inlined. Results on my machine (Windows 7 64-bit i5-3470):

Inline:      00:00:00.7351931
Call:        00:00:00.7483503
Interlocked: 00:00:04.4076651

Code:

class Program
{
    static void Swap<T>(ref T obj1, ref T obj2)
    {
        var temp = obj1;
        obj1 = obj2;
        obj2 = temp;
    }

    static void Main(string[] args)
    {
        var a = new object();
        var b = new object();

        var s = new Stopwatch();

        Swap(ref a, ref b); // JIT the swap method outside the stopwatch

        s.Restart();
        for (var i = 0; i < 500000000; i++)
        {
            var temp = a;
            a = b;
            b = temp;
        }
        s.Stop();
        Console.WriteLine("Inline temp: " + s.Elapsed);


        s.Restart();
        for (var i = 0; i < 500000000; i++)
        {
            Swap(ref a, ref b);
        }
        s.Stop();
        Console.WriteLine("Call:        " + s.Elapsed);

        s.Restart();
        for (var i = 0; i < 500000000; i++)
        {
            b = Interlocked.Exchange(ref a, b);
        }
        s.Stop();
        Console.WriteLine("Interlocked: " + s.Elapsed);

        Console.ReadKey();
    }
}

2 Comments

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.
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.
8

With C# 7, you can use tuple deconstruction to achieve the desired swap in one line, and it's clear what's going on.

decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);

(startAngle, stopAngle) = (stopAngle, startAngle);

Comments

7

For completeness, here is the binary XOR swap:

int x = 42;
int y = 51236;
x ^= y;
y ^= x;
x ^= y;

This works for all atomic objects/references, as it deals directly with the bytes, but may require an unsafe context to work on decimals or, if you're feeling really twisted, pointers. And it may be slower than a temp variable in some circumstances as well.

Comments

6

<deprecated>

You can do it in 3 lines using basic math - in my example I used multiplication, but simple addition would work also.

float startAngle = 159.9F;
float stopAngle = 355.87F;

startAngle = startAngle * stopAngle;
stopAngle = startAngle / stopAngle;
startAngle = startAngle / stopAngle;

Edit: As noted in the comments, this wouldn't work if y = 0 as it would generate a divide by zero error which I hadn't considered. So the +/- solution alternatively presented would be the best way to go.

</deprecated>


To keep my code immediately comprehensible, I'd be more likely to do something like this. [Always think about the poor guy that's gonna have to maintain your code]:

static bool Swap<T>(ref T x, ref T y)
{
    try
    {
        T t = y;
        y = x;
        x = t;
        return true;
    }
    catch
    {
        return false;
    }
}

And then you can do it in one line of code:

float startAngle = 159.9F
float stopAngle = 355.87F
Swap<float>(ref startAngle, ref stopAngle);

Or...

MyObject obj1 = new MyObject("object1");
MyObject obj2 = new MyObject("object2");
Swap<MyObject>(ref obj1, ref obj2);

Done like dinner...you can now pass in any type of object and switch them around...

7 Comments

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.
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#).
@CommuSoft: Point taken, I hadn't considered that. In that case, the +/- would surely be the better way to go.
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)?
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).
|
5

If you can change from using decimal to double you can use the Interlocked class. Presumably this will be a good way of swapping variables performance wise. Also slightly more readable than XOR.

var startAngle = 159.9d;
var stopAngle = 355.87d;
stopAngle = Interlocked.Exchange(ref startAngle, stopAngle);

Msdn: Interlocked.Exchange Method (Double, Double)

Comments

4
a = a + b
b = a - b
a = a - b

َ

Comments

4

Beware of your environment!

For example, this doesn’t seem to work in ECMAscript

y ^= x ^= y ^= x;

But this does

x ^= y ^= x; y ^= x;

My advise? Assume as little as possible.

2 Comments

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.
How is ECMAscript relevant? The question is tagged C#.
3

The simple way to swap 2 numbers in just one line:

a=(a+b)-(b=a);

eg: a=1, b=2

Step 1: a=(1+2) - (b=1)

Step 2: a=3-1

=> a=2 and b=1


Efficient way is to use:

C Programming: (x ^= y), (y ^= x), (x ^= y);

Java: x = x ^ y ^ (y = x);

Python: x, y = y, x

Note: Most common mistake people make: //Swap using bitwise XOR (Wrong Solution in C/C++)

x ^= y ^= x ^= y; 

Source: GeeksforGeek

1 Comment

proper c++: std::swap(x, y);.
3

Sometimes I wish it were possible to write a function in MSIL inline in C#, similar to how you can write inline assembler in C.

For the record, I once wrote a helper library for C# with various functions for things that were impossible to write in C# but can be written in MSIL (non-zero-based arrays for example). I had this function:

.method public hidebysig static void Swap<T> (
        !!T& a,
        !!T& b
    ) cil managed 
{
    .maxstack 4

    ldarg.1      // push a& reference
    ldarg.2      // push b& reference
    ldobj !!T    // pop b&, push b
    ldarg.2      // push b& reference
    ldarg.1      // push a& reference
    ldobj !!T    // pop a&, push a
    stobj !!T    // store a in b&
    stobj !!T    // store b in a&
    ret
}

And no locals needed. Of course this was just me being silly...

2 Comments

AFAIK with reflection you can create such function from IL instructions.
Yes obviously, but then you need to compile it every time you run the app. Anyway why would you bother? It was just for fun.
2

I hope this might help...

using System;

public class Program
{
    public static void Main()
    {
        int a = 1234;
        int b = 4321;

        Console.WriteLine("Before: a {0} and b {1}", a, b);

        b = b - a;
        a = a + b;
        b = a - b;

        Console.WriteLine("After: a {0} and b {1}", a, b);
    }
}

Comments

2

we can do that by doing a simple trick

a = 20;
b = 30;
a = a+b; // add both the number now a has value 50
b = a-b; // here we are extracting one number from the sum by sub
a = a-b; // the number so obtained in above help us to fetch the alternate number from sum
System.out.print("swapped numbers are a = "+ a+"b = "+ b);

Comments

1
startAngle = (startAngle + stopAngle) - (stopAngle = startAngle);

Comments

1

For binary types you can use this funky trick:

a %= b %= a %= b;

As long as a and b are not the exact same variable (e.g. aliases for the same memory) it works.

Comments

0

If you want to swap 2 string variables:

a = (a+b).Substring((b=a).Length);

An helper method accordingly:

public static class Foo {
    public static void SwapString (ref string a, ref string b) {
       a = (a+b).Substring((b=a).Length);
    }
}

Usage would be then:

string a="Test 1";
string b="Test 2";
Foo.SwapString(a, b);

3 Comments

Oh dear god what is that :P
@ABPerson - Any comments to take serious?
Huh? What do you mean?
0

Heres another swap function

public static void Flip(ref int a, ref int b)
{            
    b = b + a;
    a = b - (b - (b - a));
    b = -1 * (a - (a - (a - b))); 
}

1 Comment

Thank you for your interest in contributing to the Stack Overflow community. This question already has quite a few answers—including one that has been extensively validated by the community. Are you certain your approach hasn’t been given previously? If so, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient. Can you kindly edit your answer to offer an explanation?
0

this model is very useful

        var a = 10;
        var b = 20;

        (int a,int b)  c = (a,b);

        a = c.b ;
        b = c.a ;

Updated

now c# support this

            var a = 10;
            var b = 20;
            (b , a) = (a , b)

2 Comments

"now c# support this" -- The most upvoted answer (by TimothyP) is 9 years old, and shows exactly the same trick.
yeah . i just fixed my answer
-1

Here another approach in one line:

decimal a = 159.9m;
decimal b = 355.87m;

a = b + (b = a) - b;

Comments

-1

Here is some different process to swap two variables

//process one
a=b+a;
b=a-b;
a=a-b;
printf("a= %d  b=  %d",a,b);

//process two
a=5;
b=10;
a=a+b-(b=a);
printf("\na= %d  b=  %d",a,b);

//process three
a=5;
b=10;
a=a^b;
b=a^b;
a=b^a;
printf("\na= %d  b=  %d",a,b);

//process four
a=5;
b=10;
a=b-~a-1;
b=a+~b+1;
a=a+~b+1;
printf("\na= %d  b=  %d",a,b);

Comments

-2
var a = 15;
var b = -214;
a = b | !(b = a);

This works great.

Comments

-4

Very simple code for swapping two variables:

static void Main(string[] args)
{
    Console.WriteLine("Prof.Owais ahmed");
    Console.WriteLine("Swapping two variables");

    Console.WriteLine("Enter your first number ");
    int x = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("Enter your first number ");
    int y = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("your vlaue of x is="+x+"\nyour value of y is="+y);

    int z = x;
    x = y;
    y = z;

    Console.WriteLine("after Swapping value of x is="+x+"/nyour value of y is="+y);
    Console.ReadLine();
}

2 Comments

Pretty sure that z counts as a temp variable here.
@Isochronous if you move it out of function and make static It wont be temp anymore lol
-6

You can try the following code. It is much more better than the other code.

a = a + b;
b = a - b;
a = a - b;

1 Comment

This is exactly the same as several of the other answers. Some of which were added already 7 years ago!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.