在不使用临时variables的情况下交换两个variables

我希望能够在不使用C#中的临时variables的情况下交换两个variables。 可以这样做吗?

decimal startAngle = Convert.ToDecimal(159.9); decimal stopAngle = Convert.ToDecimal(355.87); // Swap each: // startAngle becomes: 355.87 // stopAngle becomes: 159.9 

首先,用C#语言交换没有临时variables是一个非常糟糕的主意

但为了答复,你可以使用这个代码:

 startAngle = startAngle + stopAngle; stopAngle = startAngle - stopAngle; startAngle = startAngle - stopAngle; 

如果两个数字差别很大,问题可能会发生。 这是由于浮点数的性质。

如果要隐藏临时variables,则可以使用实用程序方法:

 public static class Foo { public static void Swap<T> (ref T lhs, ref T rhs) { T temp = lhs; lhs = rhs; rhs = temp; } } 

交换两个variables的正确方法是:

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

换句话说, 使用一个临时variables。

你有它。 没有什么聪明的技巧,几十年来没有你的代码维护者诅咒你,没有日常WTF的参赛作品,也没有太多的时间试图弄清楚为什么你需要在一个操作,因为在最低的水平,即使是最复杂的语言function是一系列简单的操作。

只是一个非常简单,可读,易于理解, t = a; a = b; b = t; t = a; a = b; b = t; 解。

在我看来,那些试图使用技巧的开发人员,例如“不使用temp的交换variables”或者“Duff's设备”,只是试图展示它们是多么的聪明(而且不幸的是)。

我把它们比作那些只是为了在派对上看起来更有意思(而不是扩大视野)而阅读高级书籍的人。

加减法的解决scheme或基于异或的解决scheme的可读性较差,而且很可能比简单的“临时variables”解决scheme(算术/布尔运算而不是组装级别的普通移动)慢。

通过编写高质量的可读代码来执行自己和其他人的服务。

这是我的咆哮。 感谢收听 :-)

顺便说一下,我很清楚这并不能回答你的具体问题(我会为此道歉),但是在这方面有很多先例,人们已经问过要怎么做,正确的答案是“不要做“。

是的,使用这个代码:

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

这个问题很难处理任意值。 🙂

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

适用于所有types,包括string和浮动。

BenAlabaster展示了一种做可变开关的实用方法,但是不需要try-catch子句。 这个代码就够了。

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

用法与他所示的一样:

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

你也可以使用扩展方法:

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

像这样使用它:

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

这两种方法都在方法中使用临时variables,但是在进行交换的位置不需要临时variables。

一个二进制异或交换与一个详细的例子:

XOR真值表

 aba^b 0 0 0 0 1 1 1 0 1 1 1 0 

input:

 a = 4; b = 6; 

步骤1a = a ^ b

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

步骤2b = a ^ b

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

第3步a = a ^ b

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

输出:

 a = 6; b = 4; 

不在C#中。 在本地代码中,您可以使用triple-XOR交换技巧,但不能使用高级types安全的语言。 (无论如何,我听说XOR技巧实际上比在许多常见CPU体系结构中使用临时variables的速度慢。)

你应该只使用一个临时variables。 没有理由不能使用一个; 这不是有限的供应。

C#7引入了适当的Tuples ,它可以交换两个variables而不需要临时variables:

 int a = 10; int b = 2; (a, b) = (b, a); 

这将b分配给ab

为了未来的学习者和人类,我将这个更正提交给当前select的答案。

如果你想避免使用临时variables, 只有两个明智的select ,首先考虑性能和可读性。

  • 在通用的Swap方法中使用临时variables。 (绝对最佳性能,内联tempvariables旁边)
  • 使用Interlocked.Exchange 。 (在我的机器上慢了5.9倍,但如果多个线程同时交换这些variables,这是唯一的select。)

永远不应该做的事情:

  • 切勿使用浮点运算。 (缓慢,四舍五入和溢出错误,很难理解)
  • 切勿使用非基本算术。 (慢,溢出错误,难以理解) Decimal不是一个CPU原语,并导致远远超过你意识到的代码。
  • 不要使用算术周期。 或者有点黑客。 (很慢,很难理解)这是编译器的工作。 它可以为许多不同的平台进行优化。

因为每个人都喜欢硬数字,所以这是一个比较你的select的程序。 从Visual Studio外部以释放模式运行它,以便Swap内联。 我的机器上的结果(Windows 7 64位i5-3470):

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

码:

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

<弃用>

你可以使用基本的math在3行中 – 在我的例子中我使用乘法,但简单的加法也可以。

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

编辑:正如在评论中指出的,如果y = 0,这将不起作用,因为它会产生一个我没有考虑过的零除错误。 因此,+/-解决scheme是最好的select。

</弃用>


为了让我的代码能够立即被理解,我更有可能做这样的事情。 [总是想想可能要维护你的代码的可怜家伙]:

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

然后你可以在一行代码中做到这一点:

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

要么…

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

完成像晚餐…你现在可以通过任何types的对象,并切换它们…

如果你可以使用decimal变为double你可以使用Interlocked类。 大概这将是交换性能明智的一个好方法。 也比XOR稍微可读。

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

Msdn:Interlocked.Exchange方法(双,双)

为了完整起见,这里是二进制XOR交换:

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

这适用于所有的primefaces对象/引用,因为它直接处理字节,但可能需要一个不安全的上下文来处理小数,或者如果你真的感觉到扭曲,指针。 在某些情况下也可能比临时variables慢。

当心你的环境!

例如,这在ECMAscript中似乎不起作用

 y ^= x ^= y ^= x; 

但是这样做

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

我的build议? 尽可能less地假设。

在一行中交换两个数字的简单方法:

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

例如:a = 1,b = 2

步骤1:a =(1 + 2) – (b = 1)

步骤2:a = 3-1

=> a = 2和b = 1


有效的方法是使用:

C编程: (x ^= y), (y ^= x), (x ^= y);

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

Python: x, y = y, x

注:人们犯的最常见的错误: //使用按位异或(在C / C ++中错误的解决scheme)

 x ^= y ^= x ^= y; 

来源: GeeksforGeek

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

对于二进制types,你可以使用这个时髦的把戏:

 a %= b %= a %= b; 

只要a和b不是完全相同的variables(例如相同内存的别名),它就可以工作。

我希望这可以帮助…

 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); } } 
 startAngle = (startAngle + stopAngle) - (stopAngle = startAngle); 

这里另一种方法在一行中:

 decimal a = 159.9m; decimal b = 355.87m; a = b + (b = a) - b; 

我们可以做一个简单的伎俩来做到这一点

 a = 20; b = 30; a = a+b; // add both the number now a has value 50 b = ab; // here we are extracting one number from the sum by sub a = ab; // 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); 

使用C#7,您可以使用元组解构来在一行中实现所需的交换,并且清楚发生了什么。

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

这是交换两个variables的一些不同的过程

 //process one a=b+a; b=ab; a=ab; printf("a= %db= %d",a,b); //process two a=5; b=10; a=a+b-(b=a); printf("\na= %db= %d",a,b); //process three a=5; b=10; a=a^b; b=a^b; a=b^a; printf("\na= %db= %d",a,b); //process four a=5; b=10; a=b-~a-1; b=a+~b+1; a=a+~b+1; printf("\na= %db= %d",a,b); 

如果你想交换2个stringvariables:

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

在C#7中:

 (startAngle, stopAngle) = (stopAngle, startAngle); 
 var a = 15; var b = -214; a = b | !(b = a); 

这很好。

非常简单的代码来交换两个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(); } 

你可以尝试下面的代码。 它比其他代码好得多。

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