在不使用临时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;
步骤1 : a = a ^ b
a : 0100 b : 0110 a^b: 0010 = 2 = a
步骤2 : b = 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
分配给a
和b
。
为了未来的学习者和人类,我将这个更正提交给当前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;