Frage

brauchte ich eine Methode mich in einer Folge alle, aber das letzte Element zu geben. Dies ist meine aktuelle Implementierung:

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

Was ich brauche es für etwas mit allen Elementen mit Ausnahme des letzten zu tun ist. In meinem Fall habe ich eine Folge von Objekten mit verschiedenen Eigenschaften. Hiermit bestelle ich sie dann nach Datum, und dann brauche ich eine Anpassung an alle außer dem letzten Punkt zu tun (das ist die letzte nach der Bestellung wäre).

Das Ding ist, ich bin nicht zu in diese Aufzählungen und so noch und habe nicht wirklich jemand hier zu fragen, entweder: p Was ich frage mich ist, ob dies eine gute Umsetzung ist, oder wenn ich ein klein oder groß gemacht pfuschen irgendwo. Oder wenn vielleicht diese auf das Problem nehmen ist ein sonderbares, etc.

Ich denke, eine allgemeinere Implementierung ein AllExceptMaxBy Verfahren haben könnte. Da dies ist eine Art, was es ist. Die MoreLinq hat eine MaxBy und MinBy Verfahren und meine Methode Art von Notwendigkeit zu tun, die gleiche, aber jedes Element außer dem Maximum oder Minimum einen zurück.

War es hilfreich?

Lösung

Das ist heikel, als „letzte Element“ kein Markov Haltepunkt ist: Sie kann nicht sagen, dass Sie auf das letzte Element haben, bis Sie versuchen, die nächste zu bekommen. Es ist machbar, aber nur, wenn Sie nicht dauerhaft sein „hinter einem Element“ nichts ausmacht. Das ist im Grunde, was Ihre aktuelle Implementierung der Fall ist, und es sieht okay, obwohl ich es wahrscheinlich etwas anders schreiben würde.

Ein alternativer Ansatz wäre foreach zu verwenden, immer den vorher zurückgegebene Wert ergibt, wenn Sie bei der ersten Iteration waren:

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

Eine weitere Möglichkeit, näher an den Code:

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

Das vermeidet ganz so tief verschachteln (durch einen frühzeitigen Ausstieg zu tun, wenn die Sequenz leer ist) und verwendet es eine „echte“, während Bedingung statt while(true)

Andere Tipps

Ihre Implementierung sieht für mich völlig in Ordnung -. Es ist wahrscheinlich so, wie ich es tun würde,

Die einzige Vereinfachung ich in Bezug auf Ihre Situation könnte darauf hindeuten, ist die Liste, um zu bestellen andersherum (d aufsteigend anstatt absteigend). Obwohl dies in Ihrem Code nicht geeignet sein kann, würde es erlaubt Sie einfach collection.Skip(1) verwenden, um alle Elemente mit Ausnahme der jüngsten zu nehmen.

Ist dies nicht möglich, aus Gründen, die Sie nicht in Ihrem Beitrag gezeigt haben, dann Ihre aktuelle Implementierung ist überhaupt kein Problem.

Wenn Sie .NET 3.5, indem ich denke, man verwenden könnte:

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

(alte Antwort verschrottet;. Dieser Code wurde getestet und funktioniert) Es druckt
erster
zweiter
FIRST
ZWEITER
DRITTE


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);
  }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top