我希望能够交换两个变量,而无需在C#中使用临时变量。能做到吗?
decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);
// Swap each:
// startAngle becomes: 355.87
// stopAngle becomes: 159.9
我希望能够交换两个变量,而无需在C#中使用临时变量。能做到吗?
decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);
// Swap each:
// startAngle becomes: 355.87
// stopAngle becomes: 159.9
Answers:
首先,像C#那样在没有临时变量的情况下进行交换是一个非常糟糕的主意。
但是为了回答,您可以使用以下代码:
startAngle = startAngle + stopAngle;
stopAngle = startAngle - stopAngle;
startAngle = startAngle - stopAngle;
但是,如果两个数字相差很大,则四舍五入会出现问题。这是由于浮点数的性质。
如果要隐藏临时变量,可以使用实用程序方法:
public static class Foo {
public static void Swap<T> (ref T lhs, ref T rhs) {
T temp = lhs;
lhs = rhs;
rhs = temp;
}
}
交换两个变量的正确方法是:
decimal tempDecimal = startAngle;
startAngle = stopAngle;
stopAngle = tempDecimal;
换句话说,使用一个临时变量。
你有它。没有聪明的花招,没有代码的维护者来诅咒您数十年,没有进入The Daily WTF的条目,也没有花费太多的时间试图找出为什么需要一次操作,因为从最低的角度来看,甚至语言最复杂的功能是一系列简单的操作。
只是一个非常简单,易读,易于理解的t = a; a = b; b = t;
解决方案。
我认为,开发人员尝试使用技巧来“交换变量而不使用临时变量”或“ Duff的设备”,这只是在试图展示它们的聪明程度(并失败了)。
我将它们比作那些阅读精挑细选的书,仅仅是为了让他们在聚会上看起来更加有趣(而不是扩大视野)。
与简单的“临时变量”解决方案(使用算术/布尔运算而不是在装配级进行简单移动)相比,在其中添加和减去的解决方案或基于XOR的解决方案可读性较低,并且很可能会变慢。
通过编写高质量的可读代码来为自己和他人提供服务。
那是我的怒吼。谢谢收听 :-)
顺便说一句,我很清楚这不能回答您的特定问题(对此我会道歉),但是在SO上有很多先例,人们问过如何做某事,正确的答案是“不要做到”。
int a = 4, b = 6;
a ^= b ^= a ^= b;
适用于所有类型,包括字符串和浮点数。
^=
与string
或一起使用float
,因此不会与它们一起编译。
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);
两种方法都在该方法中使用一个临时变量,但是在进行交换时不需要使用临时变量。
不在C#中。在本机代码中,您也许可以使用三重XOR交换技巧,但不能使用高级类型安全语言。(无论如何,我听说XOR技巧实际上比许多常见CPU架构中使用临时变量要慢。)
您应该只使用一个临时变量。没有理由您不能使用它。这并不是说供应有限。
为了将来的学习者和人类,我将此更正提交给当前选择的答案。
如果要避免使用临时变量,则只有两个明智的选择会首先考虑性能,然后考虑可读性。
Swap
方法中使用临时变量。(绝对最佳性能,内联温度变量旁边)Interlocked.Exchange
。(在我的计算机上慢5.9倍,但这是您的唯一选择,如果多个线程将同时交换这些变量。)事情你应该永远不会做的事:
Decimal
不是CPU原语,并且导致的代码远远超出您的想象。因为每个人都喜欢硬数字,所以这里有一个程序比较您的选择。从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();
}
}
0
到寄存器中,由于指令较短,编译器会将变量与自身进行异或。在极少数情况下,通过使用较少的变量,可以避免寄存器溢出。这是编译器的工作,但是不幸的是,没有语言支持来有效地执行此操作。
在C#7中:
(startAngle, stopAngle) = (stopAngle, startAngle);
<不推荐使用>
您可以使用基本数学在3行中完成此操作-在我的示例中,我使用了乘法,但是简单的加法也可以。
float startAngle = 159.9F;
float stopAngle = 355.87F;
startAngle = startAngle * stopAngle;
stopAngle = startAngle / stopAngle;
startAngle = startAngle / stopAngle;
编辑:如注释中所述,如果y = 0则不起作用,因为它将生成除以零的错误,而我没有考虑过。因此,替代地提出的+/-解决方案将是最好的方法。
</不建议使用>
为了使我的代码立即可理解,我将更可能这样做。[总是考虑那个必须维护您的代码的可怜的人]:
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);
像晚餐一样做...您现在可以传递任何类型的物体并切换它们...
如果可以从使用更改decimal
为double
,则可以使用Interlocked
该类。据推测,这将是交换变量性能的好方法。也比XOR更具可读性。
var startAngle = 159.9d;
var stopAngle = 355.87d;
stopAngle = Interlocked.Exchange(ref startAngle, stopAngle);
当心您的环境!
例如,这似乎在ECMAscript中不起作用
y ^= x ^= y ^= x;
但这确实
x ^= y ^= x; y ^= x;
我的建议?假设尽可能少。
在一行中交换2个数字的简单方法:
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);
蟒蛇: x, y = y, x
注意:人们最容易犯的错误是: //使用按位XOR交换(C / C ++中的错误解决方案)
x ^= y ^= x ^= y;
资料来源:GeeksforGeek
std::swap(x, y);
。
我们可以做一个简单的技巧
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);
这是交换两个变量的一些不同过程
//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);
交换两个变量的非常简单的代码:
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();
}
z
这里算作一个临时变量。