Pergunta

Eu gostaria de ser capaz de trocar duas variáveis ??sem o uso de uma variável temporária em C #. isso pode ser feito?

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

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

Solução

Em primeiro lugar, trocando sem uma variável temporária em uma linguagem como C # é um idéia muito ruim .

Mas por uma questão de resposta, você pode usar este código:

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

Os problemas podem no entanto ocorrer com arredondamento se os dois números diferem em grande parte. Isto é devido à natureza de números de ponto flutuante.

Se você quiser esconder a variável temporária, você pode usar um método de utilitário:

public static class Foo {

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

Outras dicas

O direito maneira de swap de duas variáveis ??é:

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

Em outras palavras, usar uma variável temporária.

Lá você tem. Sem truques inteligentes, há mantenedores de seu código amaldiçoar-te para as próximas décadas, há entradas para The Daily WTF , e nenhuma despesa muito tempo tentando descobrir por que você precisava em uma operação de qualquer maneira uma vez que, no nível mais baixo, mesmo o recurso de linguagem mais complicada é uma série de operações simples.

Apenas uma forma muito simples, de fácil leitura, fácil de entender, a solução t = a; a = b; b = t;.

Na minha opinião, os desenvolvedores que tentam truques de uso para, por exemplo, "variáveis ??de swap sem o uso de um temp" ou "dispositivo de Duff" estão apenas tentando mostrar o quão espertos eles são (e falhando miseravelmente).

Eu comparo-os para aqueles que lêem intelectuais livros exclusivamente com o fim de parecer mais interessante em festas (em oposição a expandir seus horizontes).

Soluções onde você somar e subtrair, ou aqueles baseados em XOR, são menos legível e, provavelmente, mais lento do que uma simples solução "temp variável" (aritméticas / booleanas-ops em vez de movimentos simples a um nível de montagem).

Faça você mesmo e outros, um serviço escrevendo código legível boa qualidade.

Esse é o meu discurso. Graças para ouvir: -)

Como um aparte, estou bastante ciente de que este não responder a sua pergunta específica (e eu vou pedir desculpas por isso), mas há uma abundância de precedente no SO onde as pessoas têm perguntado como fazer algo e a resposta correta é " não fazê-lo".

Sim, use este código:

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

O problema é mais difícil para valores arbitrários. : -)

C # 7 introduziu tuplas que permite a troca de duas variáveis ??sem um temporário:

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

Isso atribui b para a e a para b.

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

funciona para todos os tipos, incluindo cordas e bóias.

BenAlabaster mostrou uma maneira prática de fazer um interruptor variável, mas a cláusula try-catch não é necessário. Este código é suficiente.

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

O uso é o mesmo que ele mostrado:

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

Você também pode usar um método de extensão:

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

Use-o assim:

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

Ambas as formas usa uma variável temporária no método, mas você não precisa a variável temporária onde você faz a troca.

Um swap XOR binário com um exemplo detalhado:

XOR tabela verdade :

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

Input:

a = 4;
b = 6;

Passo 1 : a = a ^ b

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

Passo 2 : b = a ^ b

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

Passo 3 : a = a ^ b

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

Output:

a = 6;
b = 4;

Não em C #. Em código nativo que você pode ser capaz de usar o truque de swap triple-XOR, mas não em uma linguagem de tipo seguro de alto nível. (De qualquer forma, eu ouvi que o truque XOR na verdade acaba sendo mais lento do que usando uma variável temporária em muitas arquiteturas comum da CPU.)

Você deve apenas usar uma variável temporária. Não há nenhuma razão você não pode usar um; não é como há uma oferta limitada.

Por uma questão de futuros alunos, e a humanidade, submeto essa correção para a resposta selecionada.

Se você quiser evitar o uso de variáveis ??temporários, existem apenas duas opções sensatas que levam primeira apresentação e, em seguida, a legibilidade em consideração.

  • Use uma variável temporária em um método Swap genérico. (Absolute melhor desempenho, ao lado variável TEMP em linha)
  • Interlocked.Exchange . (5,9 vezes mais lento na minha máquina, mas esta é a sua única opção se vários segmentos serão trocando essas variáveis ??simultaneamente.)

coisas que você deve não fazer:

  • aritmética de ponto uso Nunca flutuante. (Lento, arredondamento e estouro de erros, difícil de entender)
  • aritmética Nunca uso não-primitivo. (Lento, erros de estouro, difícil de entender) Decimal não é um CPU primitiva e resulta em muito mais código do que você imagina.
  • Nunca use período de aritmética. Ou hacks bits. (lento, difícil de entender) Esse é o trabalho do compilador. Ele pode otimizar para muitas plataformas diferentes.

Porque todo mundo adora números concretos, aqui está um programa que compara as suas opções. Executá-lo no modo de versão de fora Visual Studio para que Swap está embutido. Resultados na minha 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();
    }
}

Você pode fazê-lo em 3 linhas usando matemática básica -. No meu exemplo eu usei multiplicação, mas simples adição iria funcionar também

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

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

Edit: Como observado nos comentários, isso não iria funcionar se y = 0, uma vez que iria gerar uma divisão por zero erro que eu não tinha considerado. Assim, a +/- solução alternativa apresentada seria o melhor caminho a percorrer.


Para manter meu código imediatamente compreensível, eu estaria mais propensos a fazer algo assim. [Sempre penso sobre o pobre rapaz que vai ter de manter seu 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;
    }
}

E então você pode fazê-lo em uma linha de código:

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

Ou ...

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

Feito como jantar ... agora você pode passar em qualquer tipo de objeto e trocá-las por aí ...

Se você pode mudar de usar decimal para double você pode usar a classe Interlocked. Presumivelmente, esta será uma boa maneira de trocar desempenho variáveis ??sábio. Também um pouco mais legível do que XOR.

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

MSDN: Método Interlocked.Exchange (Double, Double)

Em C # 7:

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

Para completar, aqui é a troca XOR binário:

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

Isso funciona para todos os objetos / referências atômicas, como ele lida diretamente com os bytes, mas pode requerer um contexto inseguro para trabalhar em decimais ou, se você está sentindo realmente torcido, ponteiros. E pode ser mais lenta do que uma variável temporária em algumas circunstâncias também.

Cuidado com o meio ambiente!

Por exemplo, este não parece trabalho em ECMAscript

y ^= x ^= y ^= x;

Mas isso faz

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

Meu conselho? Assuma o mínimo possível.

Com C # 7, você pode usar tupla desconstrução para conseguir a troca desejada em uma linha, e é claro o que está acontecendo.

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

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

A maneira simples de troca de 2 números em apenas uma linha:

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

por exemplo: a = 1, b = 2

Passo 1: A = (1 + 2) - (b = 1)

Passo 2: a = 3-1

=> a = 2 e b = 1


forma eficiente é usar:

C Programming: (x ^= y), (y ^= x), (x ^= y);

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

Python: x, y = y, x

Nota: erro mais comum que as pessoas fazem: // Trocar usando bit a bit XOR (solução errada em C / C ++)

x ^= y ^= x ^= y; 

Fonte: GeeksforGeek

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

Para tipos binários que você pode usar esse truque funk:

a %= b %= a %= b;

Enquanto a e b não são a mesma variável exata (por exemplo, aliases para a mesma memória) ele funciona.

Espero que isso possa ajudar ...

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 fazer isso fazendo um truque simples

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

Com tuplas

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

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

Se você quiser trocar 2 variáveis ??de cadeia:

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

Um método auxiliar de acordo:

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

Uso seria então:

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

Aqui outra abordagem em uma linha:

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

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

Aqui está algum processo diferente para troca de duas variáveis ??

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

Isso funciona muito bem.

código muito simples para trocar duas variáveis:

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

Você pode tentar o seguinte código. É muito mais melhor do que o outro código.

a = a + b;
b = a - b;
a = a - b;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top