Domanda

ho bisogno di un metodo per darmi tutti, ma l'ultimo elemento in una sequenza. Questo è il mio attuale implementazione:

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

Che cosa ho bisogno per è di fare qualcosa con tutti gli elementi ad eccezione dell'ultimo. Nel mio caso ho una sequenza di oggetti con diverse proprietà. Ho poi ordinarli per data, e quindi ho bisogno di fare una rettifica a tutti loro, tranne la voce più recente (che sarebbe l'ultimo dopo l'ordinazione).

La cosa è, io non sono troppo in queste enumeratori e cose ancora e in realtà non hanno nessuno qui per chiedere uno: p Quello che mi chiedo è se questa è una buona implementazione, o se ho fatto un piccolo o grande sbagliare qualche parte. O se forse questo assumere il problema è uno strano, ecc.

Credo che un'implementazione più generale avrebbe potuto essere un metodo AllExceptMaxBy. Dal momento che è una specie di cosa si tratta. Il MoreLinq ha un MaxBy e il metodo MinBy e il mio metodo tipo di esigenza di fare lo stesso, ma tornare ogni elemento ad eccezione di quella massima o minima.

È stato utile?

Soluzione

Questo è difficile, come "ultimo elemento" non è un punto di arresto Markov: non si può dire che hai avuto modo di l'ultimo elemento fino a quando si tenta di ottenere il prossimo. E 'fattibile, ma solo se non vi dispiace essere in modo permanente "un elemento dietro". Questo è fondamentalmente ciò che l'implementazione corrente lo fa, e sembra a posto, anche se probabilmente sarei scrivo in modo leggermente diverso.

Un approccio alternativo sarebbe quella di utilizzare foreach, sempre ottenendo il valore precedentemente restituito a meno che non si erano alla prima iterazione:

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

Un'altra opzione, più vicino al codice:

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

Questo evita la nidificazione altrettanto profondamente (facendo una rapida uscita se la sequenza è vuota) e si utilizza un "vero", mentre condizioni invece di while(true)

Altri suggerimenti

L'implementazione sembra perfettamente bene per me -. È probabilmente il modo in cui lo farei

L'unica semplificazione Potrei suggerire in relazione alla vostra situazione è di ordinare la lista il contrario (vale a dire ascendente invece che discendente). Anche se questo potrebbe non essere adatto nel codice, sarebbe consentono di utilizzare semplicemente collection.Skip(1) a prendere tutte le voci tranne la più recente.

Se questo non è possibile per ragioni che non hanno mostrato nel tuo post, quindi l'implementazione corrente è affatto un problema.

Se si sta utilizzando .NET 3.5, penso che si potrebbe usare:

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

(Old risposta scartato;. Questo codice è stato testato e funziona) Esso stampa
prima
secondo
PRIMO
SECONDO
TERZO


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);
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top