سؤال

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

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
    {
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if(iterator.MoveNext())
                while(true)
                {
                    var current = iterator.Current;
                    if(!iterator.MoveNext())
                        yield break;
                    yield return current;
                }
        }
    }

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

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

أعتقد أن التنفيذ العام أكثر يمكن أن يكون AllExceptMaxBy طريقة. لأن هذا هو نوع من ما هو عليه. ال morelinq. لديه أ MaxBy و MinBy الطريقة وطريقة بلدي نوع من الحاجة إلى القيام بنفس الشيء، ولكن إرجاع كل عنصر باستثناء الحد الأقصى أو الحد الأدنى.

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

المحلول

هذا صعب، كما "العنصر الأخير" ليس نقطة توقف Markov: لا يمكنك معرفة أنك حصلت على العنصر الأخير حتى تحاول الحصول على واحد التالي. انها قابلة للتنفيذ، ولكن فقط إذا كنت لا تمانع في كونها نهائيا "عنصر واحد وراء". هذا في الأساس ما يفعله التنفيذ الحالي الخاص بك، ويبدو أنه بخير، على الرغم من أنني ربما أكتبها بطريقة مختلفة قليلا.

سيكون النهج البديل هو استخدام foreach, ، دائما تسفر عن القيمة التي تم إرجاعها مسبقا إلا إذا كنت في التكرار الأول:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    T previous = default(T);
    bool first = true;
    foreach (T element in source)
    {
        if (!first)
        {
            yield return previous;
        }
        previous = element;
        first = false;
    }
}

خيار آخر، أقرب إلى التعليمات البرمجية الخاصة بك:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    using (IEnumerator<T> iterator = source.GetEnumerator())
    {
        if(!iterator.MoveNext())
        {
            yield break;
        }
        T previous = iterator.Current;
        while (iterator.MoveNext())
        {
            yield return previous;
            previous = iterator.Current;
        }
    }
}

التي تتجنب التعشيش بعمق (عن طريق إجراء خروج مبكر إذا كان التسلسل فارغا) ويستخدم "حقيقي" أثناء الشرط بدلا من while(true)

نصائح أخرى

يبدو تنفيذك بشكل جيد تماما بالنسبة لي - ربما تكون الطريقة التي سأفعلها.

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

إذا لم يكن ذلك ممكنا لأسباب لم تظهر في مشاركتك، فسيكون تنفيذك الحالي مشكلة على الإطلاق.

إذا كنت تستخدم .NET 3.5، أعتقد أنه يمكنك استخدام:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
  return source.TakeWhile((item, index) => index < source.Count() - 1))
}
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    if (!source.Any())
    {
        yield break;
    }
    Queue<T> items = new Queue<T>();
    items.Enqueue(source.First());
    foreach(T item in source.Skip(1))
    {
        yield return items.Dequeue();
        items.Enqueue(item);
    }
}

(الإجابة القديمة ألغت؛ تم اختبار هذا الرمز ويعمل.) يطبع
أول
ثانيا
أول
ثانيا
الثالث


public static class ExtNum{
  public static IEnumerable skipLast(this IEnumerable source){
    if ( ! source.Any())
      yield break;
    for (int i = 0 ; i <=source.Count()-2 ; i++ )
      yield return source.ElementAt(i);
    yield break;
  }
}
class Program
{
  static void Main( string[] args )
  {
    Queue qq = new Queue();
    qq.Enqueue("first");qq.Enqueue("second");qq.Enqueue("third");
    List lq = new List();
    lq.Add("FIRST"); lq.Add("SECOND"); lq.Add("THIRD"); lq.Add("FOURTH");
    foreach(string s1 in qq.skipLast())
      Console.WriteLine(s1);
    foreach ( string s2 in lq.skipLast())
      Console.WriteLine(s2);
  }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top