Question

J'aimerais pouvoir échanger deux variables sans utiliser de variable temporaire en C #. Cela peut-il être fait?

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

// Swap each:
//   startAngle becomes: 355.87
//   stopAngle becomes: 159.9
Était-ce utile?

La solution

Tout d’abord, permuter sans une variable temporaire dans une langue en C # est une très mauvaise idée .

Mais pour répondre, vous pouvez utiliser ce code:

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

L’arrondissement des chiffres peut toutefois poser problème si les deux chiffres diffèrent beaucoup. Cela est dû à la nature des nombres à virgule flottante.

Si vous souhaitez masquer la variable temporaire, vous pouvez utiliser une méthode utilitaire:

public static class Foo {

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

Autres conseils

La droite méthode pour échanger deux variables est la suivante:

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

En d'autres termes, utilise une variable temporaire.

Voilà. Aucune astuce intelligente, aucun responsable de votre code ne vous maudire pendant des décennies, aucune entrée à Le WTF quotidien , et aucune dépense trop de temps à essayer de comprendre pourquoi vous en aviez besoin en une seule opération car, au plus bas niveau, même la fonctionnalité de langage la plus compliquée consiste en une série d’opérations simples.

Juste une solution très simple, lisible, facile à comprendre, t = a; a = b; b = t;.

À mon avis, les développeurs qui essaient d'utiliser des astuces pour, par exemple, & "; échanger des variables sans utiliser de temp"! <>> "; ou & "; Dispositif de Duff &"; essayons simplement de montrer à quel point ils sont intelligents (et échouent lamentablement).

Je les compare à ceux qui lisent des livres de grande lecture uniquement dans le but de paraître plus intéressants lors de fêtes (au lieu d’élargir vos horizons).

Les solutions où vous ajoutez et soustrayez, ou celles basées sur XOR, sont moins lisibles et probablement plus lentes que la simple & "variable variable &"; solution (arithmétique / boolean-ops au lieu de simples mouvements au niveau de l’assemblage).

Faites-vous, à vous et à d'autres, un service en écrivant un code lisible de bonne qualité.

C'est mon coup de gueule. Merci d'avoir écouté: -)

En passant, je suis tout à fait au courant que cela ne répond pas à votre question (et je m'en excuse), mais il existe de nombreux précédents sur SO, où les gens ont demandé comment faire quelque chose et la bonne réponse est < !> "Ne le faites pas &";

Oui, utilisez ce code:

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

Le problème est plus difficile pour les valeurs arbitraires. : -)

C # 7 a introduit tuples qui permet d'échanger deux variables sans variable temporaire:

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

Ceci assigne b à a et <=> à <=>.

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

Fonctionne pour tous les types, y compris les chaînes et les flotteurs.

BenAlabaster a montré un moyen pratique d'effectuer un changement de variable, mais la clause try-catch n'est pas nécessaire. Ce code suffit.

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

L'utilisation est la même que celle indiquée:

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

Vous pouvez également utiliser une méthode d'extension:

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

Utilisez-le comme ceci:

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

Les deux méthodes utilisent une variable temporaire dans la méthode, mais vous n'avez pas besoin de la variable temporaire dans laquelle vous effectuez le swapping.

Un échange binaire XOR avec un exemple détaillé:

Table de vérité XOR :

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

Entrée:

a = 4;
b = 6;

Étape 1 : a = a ^ b

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

Étape 2 : b = a ^ b

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

Étape 3 : a = a ^ b

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

Résultat:

a = 6;
b = 4;

Pas en C #. Dans le code natif, vous pourrez peut-être utiliser l'astuce d'échange triple-XOR, mais pas dans un langage de niveau supérieur compatible avec les caractères. (Quoi qu'il en soit, j'ai entendu dire que l'astuce XOR finissait par être plus lente que l'utilisation d'une variable temporaire dans de nombreuses architectures de CPU courantes.)

Vous devriez simplement utiliser une variable temporaire. Il n'y a aucune raison pour que vous ne puissiez pas en utiliser un; ce n'est pas comme si l'offre était limitée.

Dans l'intérêt des futurs apprenants et de l'humanité, je soumets cette correction à la réponse actuellement sélectionnée.

Si vous souhaitez éviter d'utiliser des variables temporaires, il n'y a que deux options sensibles prenant en compte les performances initiales, puis la lisibilité.

  • Utilisez une variable temporaire dans une méthode générique Swap. (Meilleure performance absolue, à côté de la variable temporaire en ligne)
  • Utilisez Interlocked.Exchange . (5,9 fois plus lente sur ma machine, mais ceci est votre seule option si plusieurs threads vont échanger ces variables simultanément.)

Ce que vous devriez ne jamais faire:

  • N'utilisez jamais d'arithmétique en virgule flottante. (erreurs lentes, d'arrondis et de débordement, difficiles à comprendre)
  • N'utilisez jamais d'arithmétique non primitive. (lentes, erreurs de débordement, difficiles à comprendre) Decimal n'est pas une primitive de l'UC et ses résultats dans beaucoup plus de code que vous réalisez.
  • N'utilisez jamais de période arithmétique. Ou des bidouilles. (lent, difficile à comprendre) C'est le travail du compilateur. Il peut optimiser pour de nombreuses plates-formes différentes.

Parce que tout le monde aime les chiffres durs, voici un programme qui compare vos options. Exécutez-le en mode édition en dehors de Visual Studio pour que <=> soit en ligne. Résultats sur ma machine (Windows 7 64 bits i5-3470):

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

Code:

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

& Lt; obsolète >

Vous pouvez le faire en 3 lignes en utilisant les mathématiques de base - dans mon exemple, j’utilisais la multiplication, mais un simple ajout fonctionnerait aussi.

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

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

Modifier: comme indiqué dans les commentaires, cela ne fonctionnerait pas si y = 0 car cela générerait une erreur de division par zéro que je n'avais pas prise en compte. Ainsi, la solution +/- présentée alternativement serait la meilleure solution.

< / obsolète >

Pour que mon code soit toujours compréhensible, je serais plus susceptible de faire quelque chose comme ça. [Pensez toujours au pauvre gars qui va devoir maintenir votre code]:

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

Et puis vous pouvez le faire en une seule ligne de code:

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

Fait comme un dîner ... vous pouvez maintenant passer dans n'importe quel type d'objet et les échanger ...

Si vous pouvez passer de decimal à double, vous pouvez utiliser la classe Interlocked. Ce sera probablement un bon moyen d’échanger les variables en termes de performances. Aussi légèrement plus lisible que XOR.

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

Msdn: méthode Interlocked.Exchange (Double, Double)

En C # 7:

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

Pour être complet, voici le swap binaire XOR:

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

Ceci fonctionne pour tous les objets / références atomiques, car il traite directement avec les octets, mais peut nécessiter un contexte non sécurisé pour travailler sur les décimales ou, si vous vous sentez vraiment tordu, les pointeurs. Et cela peut aussi être plus lent qu'une variable temporaire dans certaines circonstances.

Méfiez-vous de votre environnement!

Par exemple, cela ne & # 8217; semble pas fonctionner en ECMAscript

y ^= x ^= y ^= x;

Mais cela ne

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

Mon conseil? Supposer le moins possible.

Avec C # 7, vous pouvez utiliser la déconstruction de tuples pour réaliser l’échange souhaité sur une ligne, et le résultat est clair.

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

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

Le moyen simple d'échanger 2 nombres en une seule ligne:

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

Exemple: a = 1, b = 2

Étape 1: a = (1 + 2) - (b = 1)

Étape 2: a = 3-1

= > a = 2 et b = 1

Le moyen efficace consiste à utiliser:

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

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

Python: x, y = y, x

Remarque: Les gens commettent l'erreur la plus courante: // Permuter en utilisant XOR au bit (solution incorrecte en C / C ++)

x ^= y ^= x ^= y; 

Source: GeeksforGeek

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

& # 1614;

Pour les types binaires, vous pouvez utiliser cette astuce géniale:

a %= b %= a %= b;

Tant que a et b ne sont pas exactement la même variable (par exemple, des alias pour la même mémoire), cela fonctionne.

J'espère que cela pourrait aider ...

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

nous pouvons le faire en faisant une simple astuce

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

Avec tuples

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

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

Si vous souhaitez échanger 2 variables de chaîne:

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

Une méthode d'assistance en conséquence:

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

L’utilisation serait alors:

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

Voici une autre approche en une ligne:

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

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

Voici un processus différent pour échanger deux 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);

Cela fonctionne très bien.

Code très simple pour permuter deux 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();
}

Vous pouvez essayer le code suivant. C'est beaucoup mieux que l'autre code.

a = a + b;
b = a - b;
a = a - b;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top