سؤال

ما هي الطريقة الأكثر فعالية لكتابة المدرسة القديمة:

StringBuilder sb = new StringBuilder();
if (strings.Count > 0)
{
    foreach (string s in strings)
    {
        sb.Append(s + ", ");
    }
    sb.Remove(sb.Length - 2, 2);
}
return sb.ToString();

...في LINQ?

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

المحلول

وهذا الجواب يدل على استخدام LINQ (Aggregate) كما طلب في السؤال وليس المقصود للاستخدام اليومي.لأن هذا لا يستخدم StringBuilder وسوف يكون الأداء الرهيبة لفترة طويلة جدا متواليات.العادية استخدام رمز String.Join كما هو مبين في الآخر الجواب

استخدام مجموع الاستفسارات مثل هذا:

string[] words = { "one", "two", "three" };
var res = words.Aggregate(
   "", // start with empty string to handle empty list case.
   (current, next) => current + ", " + next);
Console.WriteLine(res);

هذه النواتج:

one, two, three

إجمالي هي وظيفة أن يأخذ مجموعة من القيم وإرجاع القيمة العددية.أمثلة من T-SQL تشمل min, max, و المبلغ.سواء VB و C# لديها دعم المجاميع.سواء VB و C# دعم المجاميع كما طرق الإرشاد.باستخدام الدوت منهج واحد يدعو ببساطة طريقة على IEnumerable الكائن.

تذكر أن إجمالي الاستفسارات يتم تنفيذها على الفور.

المزيد من المعلومات - MSDN:إجمالي الاستفسارات


إذا كنت تريد حقا أن استخدام Aggregate استخدام الخيار استخدام StringBuilder المقترحة في تعليق CodeMonkeyKing والتي سوف تكون حول نفس رمز العادية String.Join بما في ذلك الأداء الجيد لعدد كبير من الكائنات:

 var res = words.Aggregate(
     new StringBuilder(), 
     (current, next) => current.Append(current.Length == 0? "" : ", ").Append(next))
     .ToString();

نصائح أخرى

return string.Join(", ", strings.ToArray());

في صافي 4، هناك الجديدة الزائد للحصول على string.Join أن تقبل IEnumerable<string>. ان الكود ثم تبدو:

return string.Join(", ", strings);

لماذا استخدام ينق؟

string[] s = {"foo", "bar", "baz"};
Console.WriteLine(String.Join(", ", s));

وهذا يعمل تماما ويقبل أي IEnumerable<string> بقدر ما أتذكر. Aggregate لا حاجة أي شيء هنا وهو أبطأ كثيرا.

هل نظرت إلى طريقة تمديد الكلي؟

var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b);

والمثال الحقيقي من قانون بلدي:

return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b);

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

ويمكنك استخدام StringBuilder في Aggregate:

  List<string> strings = new List<string>() { "one", "two", "three" };

  StringBuilder sb = strings
    .Select(s => s)
    .Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", "));

  if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); }

  Console.WriteLine(sb.ToString());

Select هو في وجود فقط لاظهار يمكنك القيام به أكثر الاشياء LINQ).

هنا هو الجمع بين الانضمام إلى/Linq نهج لقد استقر بعد النظر في إجابات أخرى و المسائل في سؤال مماثل (أي أن المجموع الكلي لسلسلة تفشل مع 0 العناصر).

string Result = String.Join(",", split.Select(s => s.Name));

أو (إذا s ليست سلسلة)

string Result = String.Join(",", split.Select(s => s.ToString()));

  • بسيطة
  • سهلة القراءة والفهم
  • يعمل عناصر عامة
  • يسمح باستخدام الكائنات أو خصائص الكائن
  • يعالج حالة من 0-طول العناصر
  • يمكن استخدامها مع إضافية Linq تصفية
  • يؤدي بشكل جيد (على الأقل في تجربتي)
  • لا تتطلب (دليل) إنشاء الكائن (على سبيل المثال StringBuilder) لتنفيذ

وبالطبع الانضمام يعتني المزعجة النهائية الفاصلة التي في بعض الأحيان يتسلل إلى مناهج أخرى (for, foreach) ، وهذا هو السبب كنت أبحث عن Linq الحل في المقام الأول.

وبيانات الأداء سريع لب StringBuilder مباراة تحديد وحالة الإجمالية أكثر من 3000 عناصر هي:

واختبار وحدة - المدة (ثانية)
LINQ_StringBuilder - 0.0036644
LINQ_Select.Aggregate - 1.8012535

    [TestMethod()]
    public void LINQ_StringBuilder()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000;i++ )
        {
            ints.Add(i);
        }
        StringBuilder idString = new StringBuilder();
        foreach (int id in ints)
        {
            idString.Append(id + ", ");
        }
    }
    [TestMethod()]
    public void LINQ_SELECT()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000; i++)
        {
            ints.Add(i);
        }
        string ids = ints.Select(query => query.ToString())
                         .Aggregate((a, b) => a + ", " + b);
    }

وأنا دائما استخدام الأسلوب التمديد:

public static string JoinAsString<T>(this IEnumerable<T> input, string seperator)
{
    var ar = input.Select(i => i.ToString()).ToArray();
    return string.Join(seperator, ar);
}

وبواسطة '<م> فائقة باردة طريقة LINQ ' قد يكون الحديث عن الطريقة التي LINQ يجعل البرمجة الوظيفية الكثير أكثر قبولا مع استخدام طرق الإرشاد. أعني، نحوي السكر الذي يسمح الوظائف التي بالسلاسل بطريقة خطية بصريا (واحدة تلو الأخرى) بدلا من أن تعشش (واحد داخل الآخر). على سبيل المثال:

int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));

ويمكن كتابة مثل هذا:

int totalEven = myInts.Where(i => i % 2 == 0).Sum();

ويمكنك أن ترى كيف المثال الثاني هو أسهل للقراءة. يمكنك أيضا أن نرى كيف يمكن إضافة المزيد من الوظائف مع أقل من المشاكل المسافة البادئة أو <م> Lispy إغلاق أقواس تظهر في نهاية التعبير.

وهناك الكثير من الإجابات الأخرى أذكر أن String.Join هو الطريق للذهاب لأنه أسرع أو أبسط لقراءة. ولكن إذا كنت تأخذ تفسيري ل'<م> طريقة LINQ فائقة باردة ' ثم الجواب هو استخدام String.Join ولكن يكون ذلك ملفوفة في طريقة تمديد أسلوب LINQ التي من شأنها أن تسمح لك لسلسلة مهامكم في ارضاء بصريا الطريقة. حتى إذا كنت تريد أن تكتب sa.Concatenate(", ") كل ما تحتاجه لخلق شيء من هذا القبيل:

public static class EnumerableStringExtensions
{
   public static string Concatenate(this IEnumerable<string> strings, string separator)
   {
      return String.Join(separator, strings);
   }
}

وهذا سيوفر التعليمات البرمجية التي performant للمثل دعوة مباشرة (على الأقل من حيث الخوارزمية التعقيد)، وفي بعض الحالات قد جعل رمز أكثر قابلية للقراءة (حسب السياق) خصوصا إذا كان رمز آخر في كتلة يستخدم بالسلاسل على غرار وظيفة.

وهناك العديد من الإجابات البديلة في هذه السؤال السابق - الذي كان من المسلم به أن تستهدف مجموعة صحيح كمصدر، لكنه لم يتلق إجابات معممة

وهنا هو استخدام LINQ النقي كتعبير واحد:

static string StringJoin(string sep, IEnumerable<string> strings) {
  return strings
    .Skip(1)
    .Aggregate(
       new StringBuilder().Append(strings.FirstOrDefault() ?? ""), 
       (sb, x) => sb.Append(sep).Append(x));
}

وعلى لعنة جميلة بسرعة!

أنا ذاهب إلى الغش قليلا والتخلص من جديد الإجابة على هذا يبدو أن نلخص أفضل من كل شيء هنا بدلا من الخلاف داخل تعليق.

حتى تتمكن من سطر واحد هذا:

List<string> strings = new List<string>() { "one", "two", "three" };

string concat = strings        
    .Aggregate(new StringBuilder("\a"), 
                    (current, next) => current.Append(", ").Append(next))
    .ToString()
    .Replace("\a, ",string.Empty); 

تحرير: عليك إما ترغب في التحقق فارغة enumerable الأولى أو إضافة .Replace("\a",string.Empty); إلى نهاية التعبير.أعتقد أنني قد سعيت إلى الحصول على القليل جدا الذكية.

الجواب من @a.صديق قد يكون قليلا أكثر performant, لست متأكدا ما لا محل تحت غطاء محرك السيارة بالمقارنة مع إزالة.الوحيد التحذير إذا كان بعض السبب أردت أن concat السلاسل التي انتهت في \a سوف تفقد الخاص بك فواصل...أجد أنه من غير المرجح.إذا كان هذا هو الحال لديك غيرها من حروف الهوى للاختيار من بينها.

ويمكنك الجمع بين LINQ وstring.join() فعال تماما. أنا هنا إزالة عنصر من السلسلة. هناك طرق أفضل للقيام بذلك جدا ولكن هنا هو:

filterset = String.Join(",",
                        filterset.Split(',')
                                 .Where(f => mycomplicatedMatch(f,paramToMatch))
                       );

والكثير من الخيارات هنا. يمكنك استخدام LINQ وب StringBuilder حتى تحصل على الأداء أيضا مثل ذلك:

StringBuilder builder = new StringBuilder();
List<string> MyList = new List<string>() {"one","two","three"};

MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w));
return builder.ToString();

وفعلت ما يلي سريعة وقذرة عند تحليل ملف سجل IIS باستخدام LINQ، لأنها عملت @ 1000000 خطوط جيد جدا (15 ثانية)، على الرغم من أن حصلت على الخروج من الذاكرة خطأ عند محاولة 2 مليون خط.

    static void Main(string[] args)
    {

        Debug.WriteLine(DateTime.Now.ToString() + " entering main");

        // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log 
        string[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log");

        Debug.WriteLine(lines.Count().ToString());

        string[] a = lines.Where(x => !x.StartsWith("#Software:") &&
                                      !x.StartsWith("#Version:") &&
                                      !x.StartsWith("#Date:") &&
                                      !x.StartsWith("#Fields:") &&
                                      !x.Contains("_vti_") &&
                                      !x.Contains("/c$") &&
                                      !x.Contains("/favicon.ico") &&
                                      !x.Contains("/ - 80")
                                 ).ToArray();

        Debug.WriteLine(a.Count().ToString());

        string[] b = a
                    .Select(l => l.Split(' '))
                    .Select(words => string.Join(",", words))
                    .ToArray()
                    ;

        System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b);

        Debug.WriteLine(DateTime.Now.ToString() + " leaving main");

    }

وكان السبب الحقيقي كنت LINQ لمتميز () I NEEDE سابقا:

string[] b = a
    .Select(l => l.Split(' '))
    .Where(l => l.Length > 11)
    .Select(words => string.Format("{0},{1}",
        words[6].ToUpper(), // virtual dir / service
        words[10]) // client ip
    ).Distinct().ToArray()
    ;

وأنا كتبت عن هذا منذ فترة، ما فعلته طبقات لتكون بالضبط ما كنت تبحث عنه:

http://ondevelopment.blogspot.com/2009 /02/string-concatenation-made-easy.html

في بلوق وظيفة وصف كيفية تطبيق أساليب الإرشاد التي تعمل على IEnumerable وتتم تسمية سلسل، وهذا سوف تمكنك من كتابة أشياء مثل:

var sequence = new string[] { "foo", "bar" };
string result = sequence.Concatenate();

وأو أشياء أكثر تفصيلا مثل:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top