我希望能够在不使用C#中的临时变量的情况下交换两个变量。可以这样做吗?
decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);
// Swap each:
// startAngle becomes: 355.87
// stopAngle becomes: 159.9
答案 0 :(得分:210)
交换两个变量的正确方式是:
decimal tempDecimal = startAngle;
startAngle = stopAngle;
stopAngle = tempDecimal;
换句话说,使用临时变量。
你有它。没有聪明的技巧,没有你的代码的维护者在未来几十年里诅咒你,没有The Daily WTF的条目,也没有花太多时间在一个操作中找出你为什么需要它,因为在最低级别,即使是最复杂的语言功能也是一系列简单的操作。
只是一个非常简单,易读,易于理解的t = a; a = b; b = t;
解决方案。
在我看来,尝试使用技巧的开发人员,例如,“不使用临时交换变量”或“Duff的设备”只是试图表明他们有多聪明(并且悲惨地失败)。
我把它们比作那些阅读高雅书籍的人,仅仅是为了在派对上看起来更有趣(而不是扩大你的视野)。
您添加和减去的解决方案,或基于XOR的解决方案,其可读性较差,并且可能比简单的“临时变量”解决方案(算术/布尔运算而不是汇编级别的普通移动)慢。
通过编写高质量的可读代码,为自己和他人提供服务。
那是我的咆哮。感谢您的收听: - )
顺便说一句,我很清楚这不会回答你的具体问题(我会为此道歉)但是在SO上有很多先例,人们已经问过如何做某事并且正确答案是“不要这样做“。
答案 1 :(得分:102)
首先,在没有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;
}
}
答案 2 :(得分:71)
是的,请使用以下代码:
stopAngle = Convert.ToDecimal(159.9);
startAngle = Convert.ToDecimal(355.87);
任意值的问题都比较困难。 : - )
答案 3 :(得分:68)
C# 7 introduced tuples,可以在没有临时变量的情况下交换两个变量:
int a = 10;
int b = 2;
(a, b) = (b, a);
这会将b
分配给a
,将a
分配给b
。
答案 4 :(得分:43)
int a = 4, b = 6;
a ^= b ^= a ^= b;
适用于所有类型,包括字符串和浮点数。
答案 5 :(得分:19)
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);
两种方法都在方法中使用临时变量,但在交换时不需要临时变量。
答案 6 :(得分:15)
带有详细示例的二进制XOR交换:
XOR真值表:
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
<强>输入:
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;
答案 7 :(得分:11)
为了未来的学习者和人性,我将此修正提交给当前选择的答案。
如果你想避免使用临时变量,那么只有两个合理的选项可以考虑第一个性能和可读性。
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();
}
}
答案 8 :(得分:11)
不在C#中。在本机代码中,您可以使用三重XOR交换技巧,但不能使用高级类型安全语言。 (无论如何,我听说XOR技巧实际上比在许多常见CPU架构中使用临时变量要慢。)
您应该只使用临时变量。没有理由你不能使用它;它不像供应有限。
答案 9 :(得分:7)
&LT;弃用&GT;
你可以使用基本数学在3行中完成 - 在我的例子中我使用了乘法,但是简单的加法也可以。
float startAngle = 159.9F;
float stopAngle = 355.87F;
startAngle = startAngle * stopAngle;
stopAngle = startAngle / stopAngle;
startAngle = startAngle / stopAngle;
编辑:如评论中所述,如果y = 0,这将无效,因为它会产生除以零的错误,我没有考虑过。所以+/-解决方案交替呈现将是最好的方式。
&LT; /弃用&GT;
为了让我的代码立即易于理解,我更有可能做这样的事情。 [总是想想那个必须维护代码的穷人]:
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);
像晚餐一样......你现在可以传递任何类型的物体并将它们切换到......
答案 10 :(得分:6)
如果您可以使用decimal
更改为double
,则可以使用Interlocked
课程。
据推测,这将是明智地交换变量性能的好方法。也比XOR稍微更具可读性。
var startAngle = 159.9d;
var stopAngle = 355.87d;
stopAngle = Interlocked.Exchange(ref startAngle, stopAngle);
答案 11 :(得分:6)
在C#7中:
(startAngle, stopAngle) = (stopAngle, startAngle);
答案 12 :(得分:5)
谨防您的环境!
例如,这似乎不适用于ECMAscript
y ^= x ^= y ^= x;
但这确实
x ^= y ^= x; y ^= x;
我的建议?假设尽可能少。
答案 13 :(得分:5)
为了完整性,这里是二进制XOR交换:
int x = 42;
int y = 51236;
x ^= y;
y ^= x;
x ^= y;
这适用于所有原子对象/引用,因为它直接处理字节,但可能需要一个不安全的上下文来处理小数,或者,如果你感觉真的扭曲,指针。在某些情况下,它可能比临时变量慢。
答案 14 :(得分:5)
使用C#7,您可以使用元组解构来在一行中实现所需的交换,并且很明显发生了什么。
decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);
(startAngle, stopAngle) = (stopAngle, startAngle);
答案 15 :(得分:3)
a = a + b
b = a - b
a = a - b
答案 16 :(得分:3)
在一行中交换2个数字的简单方法:
a=(a+b)-(b=a);
例如:a = 1,b = 2
步骤1:a =(1 + 2) - (b = 1)
步骤2:a = 3-1
=&GT; a = 2且b = 1
有效的方法是使用:
C编程:(x ^= y), (y ^= x), (x ^= y);
Java:x = x ^ y ^ (y = x);
Python:x, y = y, x
注意:人们犯的最常见错误: //使用按位XOR交换(C / C ++中的错误解决方案)
x ^= y ^= x ^= y;
来源:GeeksforGeek
答案 17 :(得分:2)
我希望这可能会有所帮助......
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);
}
}
答案 18 :(得分:2)
对于二进制类型,您可以使用这个时髦的技巧:
a %= b %= a %= b;
只要a和b不是完全相同的变量(例如同一内存的别名),它就可以工作。
答案 19 :(得分:2)
我们可以通过做一个简单的技巧来做到这一点
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);
答案 20 :(得分:1)
startAngle = (startAngle + stopAngle) - (stopAngle = startAngle);
答案 21 :(得分:1)
使用元组
decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);
(startAngle, stopAngle) = (stopAngle, startAngle);
答案 22 :(得分:1)
如果要交换2个字符串变量:
a = (a+b).Substring((b=a).Length);
相应的辅助方法:
public static class Foo {
public static void SwapString (ref string a, ref string b) {
a = (a+b).Substring((b=a).Length);
}
}
然后用法:
string a="Test 1";
string b="Test 2";
Foo.SwapString(a, b);
答案 23 :(得分:0)
有时我希望可以在 C# 中内联 MSIL 中编写函数,类似于在 C 中编写内联汇编程序的方式。
作为记录,我曾经为 C# 编写了一个辅助库,其中包含各种函数,用于在 C# 中无法编写但可以在 MSIL 中编写的内容(例如非零数组) .我有这个功能:
.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
}
而且不需要当地人。当然这只是我傻...
答案 24 :(得分:0)
以下是交换两个变量的一些不同过程
//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);
答案 25 :(得分:0)
这是另一种方法:
if (( ($release =~ /5\.(\d)/) && ($1 > 3) ) && (($version =~ m/R(\d)/) && ($1 >= 3) ) )
{
print "OK\n";
}
答案 26 :(得分:-2)
var a = 15;
var b = -214;
a = b | !(b = a);
这很有效。
答案 27 :(得分:-4)
您可以尝试以下代码。它比其他代码好得多。
a = a + b;
b = a - b;
a = a - b;
答案 28 :(得分:-4)
交换两个变量的非常简单的代码:
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();
}