سؤال

أود أن أكون قادرًا على تبديل متغيرين دون استخدام متغير مؤقت في C#.هل يمكن هذا؟

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

// Swap each:
//   startAngle becomes: 355.87
//   stopAngle becomes: 159.9
هل كانت مفيدة؟

المحلول

بادئ ذي بدء، المبادلة بدون متغير مؤقت في لغة مثل 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;

وبعبارة أخرى، <م> استخدام متغير مؤقت.

وهناك لديك. لا حيل ذكية، لا مشرفون من التعليمات البرمجية شتم لكم لعقود قادمة، لا إدخالات إلى صحيفة ديلي WTF ، وليس الإنفاق الكثير من الوقت في محاولة لمعرفة لماذا كنت في حاجة في عملية واحدة على أي حال منذ ذلك الحين، في أدنى مستوى، حتى ميزة اللغة الأكثر تعقيدا هو عبارة عن سلسلة من العمليات البسيطة.

ومجرد بسيطة جدا، ويمكن قراءتها، سهلة الفهم، t = a; a = b; b = t; حل.

في رأيي، للمطورين الذين يحاولون استخدام الحيل، على سبيل المثال، "المتغيرات مبادلة دون استخدام مؤقت" أو "جهاز داف" هي مجرد محاولة لاظهار كيف ذكي أنهم (والفشل ذريعا).

واشبه لهم أولئك الذين يقرأون الكتب الراقية والمحترمة فقط لغرض يبدو أكثر إثارة للاهتمام في الأطراف (في مقابل توسيع آفاقك).

وحلول حيث يمكنك جمع وطرح، أو تلك القائمة على XOR، هي أقل قابلية للقراءة وأكثر أبطأ عرضة من بسيطة "مؤقت متغير" حل (الحساب / منطقية مكتب خدمات المشاريع بدلا من تحركات واضحة على مستوى التجميع).

ولنفسك، والآخرين، وهي خدمة من خلال كتابة نوعية جيدة متاحة للقراءة.

وهذا هو بلدي خرف. شكرا لإصغائكم: -)

وبوصفها جانبا، وأنا أدرك تماما هذا لا يجيب على سؤالك المحدد (وأنا أعتذر عن ذلك) ولكن هناك الكثير من سابقة على SO حيث يطلب من الناس كيفية القيام بشيء ما والجواب الصحيح هو " لا تفعل ذلك ".

نعم، استخدم هذا الرمز:

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

والمشكلة هي أصعب للقيم التعسفية. : -)

تم تقديم C#7 الصفوف والتي تمكن من تبديل متغيرين دون متغير مؤقت:

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

هذا يعين b ل a و a ل b.

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

ويعمل لجميع أنواع بما في ذلك سلاسل وعوامات.

وBenAlabaster أظهرت وسيلة عملية للقيام مفتاح متغير، ولكن ليست هناك حاجة للبند محاولة اللحاق. هذا الرمز هو بما فيه الكفاية.

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

وكلا الاتجاهين يستخدم متغير مؤقت في الأسلوب، ولكنك لا تحتاج إلى متغير مؤقتة حيث يمكنك القيام مبادلة.

مبادلة XOR الثنائية مع مثال تفصيلي:

جدول الحقيقة XOR:

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

مدخل:

a = 4;
b = 6;

الخطوة 1: أ = أ ^ ب

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

الخطوة 2: ب = أ ^ ب

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

الخطوه 3: أ = أ ^ ب

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

انتاج:

a = 6;
b = 4;

وليس في C #. في التعليمات البرمجية الأصلية التي قد تكون قادرة على استخدام الثلاثي XOR تبادل خدعة، ولكن ليس في لغة من نوع آمن مستوى عال. (على أي حال، لقد سمعت أن الحيلة XOR ينتهي فعليا حتى تكون أبطأ من استخدام متغير مؤقت في العديد من أبنية وحدة المعالجة المركزية المشتركة).

ويجب عليك فقط استخدام متغير مؤقت. ليس هناك سبب لا يمكنك استخدام واحد؛ انها ليست مثل هناك كمية محدودة.

من أجل المتعلمين في المستقبل، ومن أجل الإنسانية، أقدم هذا التصحيح للإجابة المحددة حاليًا.

إذا كنت تريد تجنب استخدام المتغيرات المؤقتة، فهناك خياران معقولان فقط التي تأخذ الأداء الأول ثم سهولة القراءة في الاعتبار.

  • استخدم متغيرًا مؤقتًا بشكل عام Swap طريقة.(أفضل أداء على الإطلاق، بجوار متغير درجة الحرارة المضمّن)
  • يستخدم Interlocked.Exchange.(أبطأ بـ 5.9 مرة على جهازي، ولكن هذا هو خيارك الوحيد إذا كانت سلاسل العمليات المتعددة ستقوم بتبديل هذه المتغيرات في وقت واحد.)

الأشياء التي يجب عليك أبداً يفعل:

  • لا تستخدم أبدًا حساب النقطة العائمة.(أخطاء بطيئة وتقريبية وتجاوزية، يصعب فهمها)
  • لا تستخدم أبدًا العمليات الحسابية غير البدائية.(بطيئة، أخطاء تجاوز السعة، من الصعب أن نفهم) Decimal ليست وحدة بدائية لوحدة المعالجة المركزية وتنتج تعليمات برمجية أكثر بكثير مما تدرك.
  • لا تستخدم الفترة الحسابية أبدًا. أو الخارقة قليلا. (بطيء، يصعب فهمه) هذه هي مهمة المترجم.يمكنه التحسين للعديد من المنصات المختلفة.

لأن الجميع يحب الأرقام الصعبة، إليك برنامج يقارن بين خياراتك.قم بتشغيله في وضع الإصدار من خارج 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();
    }
}

<إهمال>

ويمكنك أن تفعل ذلك في 3 خطوط باستخدام الرياضيات الأساسية - في بلدي على سبيل المثال اعتدت الضرب، ولكن إضافة بسيطة تعمل أيضا

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

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

وتحرير: وكما لوحظ في التعليقات، وهذا لن يجدي نفعا إذا ص = 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);

MSDN: Interlocked.Exchange أسلوب (مزدوجة، مزدوجة)

في C # 7:

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

لاكتمال، وهنا هو تبادل XOR ثنائي:

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

وهذا يعمل لكافة الكائنات / المراجع الذرية، كما أنها تتعامل مباشرة مع بايت، ولكن قد تتطلب سياق غير آمنة للعمل على الكسور العشرية، أو إذا كنت تشعر الملتوية حقا، المؤشرات. وأنه قد يكون أبطأ من متغير درجة الحرارة في بعض الحالات أيضا.

احذر من بيئتك!

على سبيل المثال، يبدو أن هذا لا يعمل في ECMAscript

y ^= x ^= y ^= x;

ولكن هذا لا

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

نصيحتي؟افترض أقل قدر ممكن.

ومع C # 7، يمكنك استخدام الصفوف (tuple) التفكيكية لتحقيق تبادل المطلوب في سطر واحد، وأنه من الواضح ما يجري.

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

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

الطريقة البسيطة لمبادلة رقمين في سطر واحد فقط:

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

على سبيل المثال:أ=1، ب=2

الخطوة 1:أ=(1+2) - (ب=1)

الخطوة 2:أ=3-1

=> أ=2 و ب=1


الطريقة الفعالة هي استخدام:

البرمجة ج: (x ^= y), (y ^= x), (x ^= y);

جافا: x = x ^ y ^ (y = x);

بايثون: x, y = y, x

ملحوظة: الأخطاء الأكثر شيوعًا التي يرتكبها الناس:// المبادلة باستخدام bitwise XOR (حل خاطئ في C/C++)

x ^= y ^= x ^= y; 

مصدر: GeeksforGeek

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

لأنواع الثنائية يمكنك استخدام هذه الحيلة غير تقليدي:

a %= b %= a %= b;

وطالما أ و ب ليست هي نفسها المتغير المحدد (مثل الأسماء المستعارة لنفس الذاكرة) يعمل.

وآمل أن يكون هذا قد يساعد ...

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

ويمكننا أن نفعل ذلك عن طريق القيام خدعة بسيطة

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

ومع الصفوف

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

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

إذا كنت تريد مبادلة المتغيرات 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);

وهنا طريقة أخرى في سطر واحد:

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

a = b + (b = a) - 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);
var a = 15;
var b = -214;
a = b | !(b = a);

وهذا يعمل كبيرة.

ورمز بسيط جدا لمبادلة اثنين من المتغيرات:

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

ويمكنك محاولة التعليمة البرمجية التالية. فمن الأفضل أكثر بكثير من تعليمات برمجية أخرى.

a = a + b;
b = a - b;
a = a - b;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top