سؤال

كثيرًا ما أجد نفسي أكتب كودًا مثل هذا:

List<int> list = new List<int> { 1, 3, 5 };
foreach (int i in list) {
    Console.Write("{0}\t", i.ToString()); }
Console.WriteLine();

من الأفضل أن يكون شيء مثل هذا:

List<int> list = new List<int> { 1, 3, 5 };
Console.WriteLine("{0}\t", list);

أظن أن هناك طريقة ذكية للقيام بذلك، لكنني لا أرى ذلك.هل يوجد حل أفضل من الكتلة الأولى؟

هل كانت مفيدة؟

المحلول

افعل هذا:

list.ForEach(i => Console.Write("{0}\t", i));

يحرر:بالنسبة للآخرين الذين استجابوا - فهو يريدهم جميعًا على نفس الخط، مع وجود علامات تبويب بينهم.:)

نصائح أخرى

نهج مختلف، فقط للركلات:

Console.WriteLine(string.Join("\t", list));

إذا كان هناك جزء من التعليمات البرمجية تكرره طوال الوقت وفقًا لـ "لا تكرر نفسك"، فيجب عليك وضعه في مكتبتك الخاصة واستدعاء ذلك.مع أخذ ذلك في الاعتبار، هناك جانبان للحصول على الإجابة الصحيحة هنا.الأول هو الوضوح والإيجاز في الكود الذي يستدعي وظيفة المكتبة.والثاني هو الآثار المترتبة على أداء foreach.

دعونا أولاً نفكر في الوضوح والإيجاز في رمز الاتصال.

يمكنك القيام بالبحث بعدة طرق:

  1. لحلقة
  2. حلقة foreach
  3. Collection.ForEach

من بين جميع الطرق لعمل قائمة foreach. لكل مع لامبا هو أوضح وأقصر.

list.ForEach(i => Console.Write("{0}\t", i));

لذا، في هذه المرحلة قد يبدو أن List.ForEach هو الطريق الصحيح.ولكن ما هو أداء هذا؟صحيح أنه في هذه الحالة، سيحكم وقت الكتابة إلى وحدة التحكم أداء الكود.عندما نعرف شيئًا عن أداء ميزة لغة معينة، يجب علينا بالتأكيد أن نأخذها في الاعتبار على الأقل.

وفق قياسات داستون كامبل لأداء foreach أسرع طريقة لتكرار القائمة ضمن التعليمات البرمجية المُحسّنة هي استخدام حلقة for بدون استدعاء List.Count.

ومع ذلك، فإن الحلقة for عبارة عن بناء مطول.يُنظر إليها أيضًا على أنها طريقة متكررة جدًا لفعل الأشياء التي لا تتوافق مع الاتجاه الحالي نحو التعابير الوظيفية.

فهل يمكننا الحصول على الإيجاز والوضوح والأداء؟يمكننا ذلك باستخدام طريقة التمديد.في عالم مثالي، يمكننا إنشاء طريقة ملحقة على وحدة التحكم تأخذ قائمة وتكتبها باستخدام محدد.لا يمكننا القيام بذلك لأن وحدة التحكم هي فئة ثابتة وطرق الامتداد تعمل فقط على مثيلات الفئات.بدلًا من ذلك، نحتاج إلى وضع طريقة الامتداد في القائمة نفسها (حسب اقتراح David B):

public static void WriteLine(this List<int> theList)
{
  foreach (int i in list)
  {
    Console.Write("{0}\t", t.ToString());
  }
  Console.WriteLine();
}

سيتم استخدام هذا الرمز في العديد من الأماكن لذا يجب علينا إجراء التحسينات التالية:

  • بدلًا من استخدام foreach، يجب علينا استخدام أسرع طريقة لتكرار المجموعة وهي عبارة عن حلقة for مع عدد مخبأ.
  • حاليًا، يمكن تمرير القائمة فقط كوسيطة.كوظيفة مكتبة يمكننا تعميمها من خلال قدر بسيط من الجهد.
  • استخدام القائمة يحدنا من القوائم فقط، واستخدام IList يسمح لهذا الكود بالعمل مع المصفوفات أيضًا.
  • نظرًا لأن طريقة الامتداد ستكون موجودة على قائمة IList، فإننا نحتاج إلى تغيير الاسم لتوضيح ما نكتب إليه:

إليك كيف سيبدو رمز الوظيفة:

public static void WriteToConsole<T>(this IList<T> collection)
{
    int count = collection.Count();
    for(int i = 0;  i < count; ++i)
    {
        Console.Write("{0}\t", collection[i].ToString(), delimiter);
    }
    Console.WriteLine();
}

يمكننا تحسين هذا بشكل أكبر من خلال السماح للعميل بالمرور في المحدد.يمكننا بعد ذلك توفير وظيفة ثانية تكتب لوحدة التحكم باستخدام المحدد القياسي مثل هذا:

public static void WriteToConsole<T>(this IList<T> collection)
{
    WriteToConsole<T>(collection, "\t");
}

public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
{
    int count = collection.Count();
    for(int i = 0;  i < count; ++i)
    {
         Console.Write("{0}{1}", collection[i].ToString(), delimiter);
    }
    Console.WriteLine();
}

والآن، نظرًا لأننا نريد طريقة مختصرة وواضحة لكتابة القوائم على وحدة التحكم، فلدينا واحدة.إليك كود المصدر بالكامل بما في ذلك عرض توضيحي لاستخدام وظيفة المكتبة:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleWritelineTest
{
    public static class Extensions
    {
        public static void WriteToConsole<T>(this IList<T> collection)
        {
            WriteToConsole<T>(collection, "\t");
        }

        public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
        {
            int count = collection.Count();
            for(int i = 0;  i < count; ++i)
            {
                Console.Write("{0}{1}", collection[i].ToString(), delimiter);
            }
            Console.WriteLine();
        }
    }

    internal class Foo
    {
        override public string ToString()
        {
            return "FooClass";
        }
    }

    internal class Program
    {

        static void Main(string[] args)
        {
            var myIntList = new List<int> {1, 2, 3, 4, 5};
            var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4};
            var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6};
            var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()};
            // Using the standard delimiter /t
            myIntList.WriteToConsole();
            myDoubleList.WriteToConsole();
            myDoubleArray.WriteToConsole();
            myFooList.WriteToConsole();
            // Using our own delimiter ~
            myIntList.WriteToConsole("~");
            Console.Read();
        }
    }
}

=======================================================

قد تعتقد أن هذا يجب أن يكون نهاية الجواب.ومع ذلك، هناك جزء آخر من التعميم الذي يمكن القيام به.ليس من الواضح من سؤال Fatcat ما إذا كان يكتب دائمًا إلى وحدة التحكم.ربما يجب القيام بشيء آخر في foreach.في هذه الحالة، فإن إجابة جيسون بونتينج ستعطي تلك العمومية.وهنا جوابه مرة أخرى:

list.ForEach(i => Console.Write("{0}\t", i));

وذلك ما لم نجري تحسينًا آخر على طرق الامتداد الخاصة بنا ونضيف FastForEach على النحو التالي:

public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform)
    {
        int count = collection.Count();
        for (int i = 0; i < count; ++i)
        {
            actionToPerform(collection[i]);    
        }
        Console.WriteLine();
    }

يتيح لنا ذلك تنفيذ أي تعليمات برمجية عشوائية على كل عنصر في المجموعة باستخدام أسرع طريقة التكرار الممكنة.

يمكننا أيضًا تغيير وظيفة WriteToConsole لاستخدام FastForEach

public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
{
     collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter));
}

إذن، كود المصدر بالكامل، بما في ذلك مثال لاستخدام FastForEach، هو:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleWritelineTest
{
    public static class Extensions
    {
        public static void WriteToConsole<T>(this IList<T> collection)
        {
            WriteToConsole<T>(collection, "\t");
        }

        public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
        {
             collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter));
        }

        public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform)
        {
            int count = collection.Count();
            for (int i = 0; i < count; ++i)
            {
                actionToPerform(collection[i]);    
            }
            Console.WriteLine();
        }
    }

    internal class Foo
    {
        override public string ToString()
        {
            return "FooClass";
        }
    }

    internal class Program
    {

        static void Main(string[] args)
        {
            var myIntList = new List<int> {1, 2, 3, 4, 5};
            var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4};
            var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6};
            var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()};

            // Using the standard delimiter /t
            myIntList.WriteToConsole();
            myDoubleList.WriteToConsole();
            myDoubleArray.WriteToConsole();
            myFooList.WriteToConsole();

            // Using our own delimiter ~
            myIntList.WriteToConsole("~");

            // What if we want to write them to separate lines?
            myIntList.FastForEach(item => Console.WriteLine(item.ToString()));
            Console.Read();
        }
    }
}

قائمة جديدة { 1, 3, 5 }.ForEach(Console.WriteLine);

        List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
        a.ForEach(p => Console.WriteLine(p));

يحرر:اهه لقد سبقني لذلك.

list.ForEach(x=>Console.WriteLine(x));
List<int> list = new List<int> { 1, 3, 5 };
list.ForEach(x => Console.WriteLine(x));

يحرر:اللعنة!استغرق فتح الاستوديو المرئي وقتًا طويلاً لاختباره.

كما يمكنك الانضمام إلى:

var qwe = new List<int> {5, 2, 3, 8};
Console.WriteLine(string.Join("\t", qwe));
public static void WriteLine(this List<int> theList)
{
  foreach (int i in list)
  {
    Console.Write("{0}\t", t.ToString());
  }
  Console.WriteLine();
}

ثم في وقت لاحق...

list.WriteLine();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top