Pregunta

Me gustaría poder intercambiar dos variables sin el uso de una variable temporal en C#.Se puede hacer esto?

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

// Swap each:
//   startAngle becomes: 355.87
//   stopAngle becomes: 159.9
¿Fue útil?

Solución

En primer lugar, el intercambio sin una variable temporal en un lenguaje como C # es una muy mala idea .

Pero en aras de la respuesta, puede usar este código:

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

Sin embargo, pueden surgir problemas con el redondeo si los dos números difieren en gran medida. Esto se debe a la naturaleza de los números de coma flotante.

Si desea ocultar la variable temporal, puede usar un método de utilidad:

public static class Foo {

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

Otros consejos

La forma correcta de intercambiar dos variables es:

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

En otras palabras, usa una variable temporal.

Ahí lo tienes. Sin trucos inteligentes, sin mantenedores de su código que lo maldicen en las próximas décadas, sin entradas en The Daily WTF , y sin gastos demasiado tiempo tratando de averiguar por qué lo necesitaba en una operación de todos modos, ya que, en el nivel más bajo, incluso la característica de lenguaje más complicada es una serie de operaciones simples.

Solo una muy simple, legible, fácil de entender, t = a; a = b; b = t; solución.

En mi opinión, los desarrolladores que intentan usar trucos para, por ejemplo, " intercambiar variables sin usar una temp " o " dispositivo de Duff " solo intentan mostrar cuán inteligentes son (y fallan miserablemente).

Los comparo con aquellos que leen libros de alto nivel con el único propósito de parecer más interesantes en las fiestas (en lugar de expandir sus horizontes).

Las soluciones donde sumas y restas, o las basadas en XOR, son menos legibles y probablemente más lentas que una simple " variable temporal " solución (operaciones aritméticas / booleanas en lugar de movimientos simples a nivel de ensamblaje).

Bríndele a usted y a otros un servicio escribiendo código legible de buena calidad.

Esa es mi queja. Gracias por escuchar :-)

Como comentario aparte, soy bastante consciente de que esto no responde a su pregunta específica (y me disculparé por eso) pero hay muchos precedentes sobre SO donde la gente ha preguntado cómo hacer algo y la respuesta correcta es < !> quot; ¡No lo hagas " ;.

Sí, use este código:

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

El problema es más difícil para los valores arbitrarios. :-)

C# 7 introducido tuplas que permite intercambiar dos variables sin una temporal:

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

Esto asigna b a a y a a b.

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

Funciona para todos los tipos, incluidas cadenas y flotantes.

BenAlabaster mostró una forma práctica de hacer un cambio variable, pero la cláusula try-catch no es necesaria. Este código es suficiente.

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

El uso es el mismo que se muestra:

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

También podría usar un método de extensión:

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

Úselo así:

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

Ambas formas utilizan una variable temporal en el método, pero no necesita la variable temporal donde realiza el intercambio.

Un intercambio binario de XOR con un ejemplo detallado:

Tabla de verdad XOR :

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

Input:

a = 4;
b = 6;

Paso 1 : a = a ^ b

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

Paso 2 : b = a ^ b

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

Paso 3 : a = a ^ b

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

Salida :

a = 6;
b = 4;

No en C #. En el código nativo, es posible que pueda utilizar el truco de intercambio triple-XOR, pero no en un lenguaje seguro de tipo de alto nivel. (De todos modos, escuché que el truco XOR en realidad termina siendo más lento que usar una variable temporal en muchas arquitecturas de CPU comunes).

Deberías usar una variable temporal. No hay razón para que no puedas usar uno; no es que haya un suministro limitado.

Por el bien de los futuros estudiantes y la humanidad, presento esta corrección a la respuesta seleccionada actualmente.

Si desea evitar el uso de variables temporales, hay solo dos opciones sensatas que tienen en cuenta primero el rendimiento y luego la legibilidad.

  • Use una variable temporal en un método genérico Swap. (Mejor rendimiento absoluto, junto a la variable temporal en línea)
  • Utilice Interlocked.Exchange . (5.9 veces más lento en mi máquina, pero esta es su única opción si varios hilos intercambiarán estas variables simultáneamente).

Cosas que nunca debe hacer:

  • Nunca use aritmética de coma flotante. (errores lentos, de redondeo y desbordamiento, difíciles de entender)
  • Nunca use aritmética no primitiva. (lento, errores de desbordamiento, difícil de entender) Decimal no es una CPU primitiva y los resultados en mucho más código del que crees.
  • Nunca use el período aritmético. O hacks de bits. (lento, difícil de entender) Ese es el trabajo del compilador. Se puede optimizar para muchas plataformas diferentes.

Debido a que a todos les encantan los números duros, aquí hay un programa que compara sus opciones. Ejecútelo en modo de lanzamiento desde fuera de Visual Studio para que <=> esté en línea. Resultados en mi máquina (Windows 7 64-bit i5-3470):

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

Código:

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

< en desuso >

Puedes hacerlo en 3 líneas usando matemática básica; en mi ejemplo, utilicé la multiplicación, pero la suma simple también funcionaría.

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

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

Editar: Como se señaló en los comentarios, esto no funcionaría si y = 0, ya que generaría un error de división por cero que no había considerado. Por lo tanto, la solución +/- presentada alternativamente sería la mejor opción.

< / en desuso >


Para mantener mi código inmediatamente comprensible, es más probable que haga algo como esto. [Siempre piensa en el pobre tipo que tendrá que mantener tu código]:

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

Y luego puede hacerlo en una línea de código:

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

O ...

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

Hecho como la cena ... ahora puedes pasar cualquier tipo de objeto y cambiarlos ...

Si puede cambiar de usar decimal a double puede usar la clase Interlocked. Presumiblemente, esta será una buena forma de intercambiar variables de rendimiento inteligente. También un poco más legible que XOR.

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

Msdn: Interlocked.Exchange Method (Double, Double)

En C # 7:

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

Para completar, aquí está el intercambio binario de XOR:

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

Esto funciona para todos los objetos / referencias atómicas, ya que trata directamente con los bytes, pero puede requerir un contexto inseguro para trabajar en decimales o, si se siente realmente retorcido, punteros. Y puede ser más lento que una variable temporal en algunas circunstancias también.

¡Cuidado con su entorno!

Por ejemplo, esto no & # 8217; parece que no funciona en ECMAscript

y ^= x ^= y ^= x;

Pero esto sí

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

¿Mi consejo? Suponga lo menos posible.

Con C # 7, puede usar la deconstrucción de tuplas para lograr el intercambio deseado en una línea, y está claro lo que está sucediendo.

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

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

La forma sencilla de intercambiar 2 números en una sola línea:

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

por ejemplo: a = 1, b = 2

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

Paso 2: a = 3-1

= > a = 2 y b = 1


Una forma eficiente es usar:

Programación en C: (x ^= y), (y ^= x), (x ^= y);

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

Python: x, y = y, x

Nota: error más común que cometen las personas: // Intercambia usando XOR bit a bit (Solución incorrecta en C / C ++)

x ^= y ^= x ^= y; 

Fuente: GeeksforGeek

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

& # 1614;

Para los tipos binarios puedes usar este truco funky:

a %= b %= a %= b;

Siempre que ayb no sean exactamente la misma variable (por ejemplo, alias para la misma memoria) funciona.

Espero que esto pueda ayudar ...

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

podemos hacerlo haciendo un simple truco

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

Con tuplas

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

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

Si desea intercambiar 2 variables de cadena:

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

Un método auxiliar en consecuencia:

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

El uso sería entonces:

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

Aquí otro enfoque en una línea:

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

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

Aquí hay un proceso diferente para intercambiar dos 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);
var a = 15;
var b = -214;
a = b | !(b = a);

Esto funciona muy bien.

Código muy simple para intercambiar dos 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();
}

Puedes probar el siguiente código. Es mucho mejor que el otro código.

a = a + b;
b = a - b;
a = a - b;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top