Pregunta

que necesitaba un método para darme todos excepto el último elemento de una secuencia. Este es mi implementación actual:

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

Lo que necesito para es hacer algo con todos los elementos, excepto el último. En mi caso tengo una secuencia de objetos con diversas propiedades. Entonces les ordeno por fecha, y luego tengo que hacer un ajuste a todos ellos, excepto el artículo más reciente (que sería el último después de ordenar).

La cosa es que no soy demasiado en estos encuestadores y cosas todavía y realmente no tienen a nadie aquí para pedir o bien: P Lo que me pregunto es si esto es una buena aplicación, o si he hecho una pequeña o grande cometer un error en alguna parte. O si tal vez esta toma en el problema es raro, etc.

supongo que una aplicación más general podría haber sido un método AllExceptMaxBy. Dado que es una especie de lo que es. El MoreLinq tiene una MaxBy y el método MinBy y mi método de tipo de necesidad de hacer lo mismo, pero devolver todos los elementos excepto el máximo o mínimo.

¿Fue útil?

Solución

Esto es complicado, como "último elemento" no es un punto de parada de Markov: no se puede decir que tienes hasta el último elemento hasta que se intenta obtener el siguiente. Es factible, pero sólo si no te importa estar permanentemente "un elemento detrás". Eso es básicamente lo que hace su implementación actual, y se ve bien, aunque probablemente me escribo un poco diferente.

Un enfoque alternativo sería utilizar foreach, siempre dando el valor devuelto previamente a menos que estuviera en la primera iteración:

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

Otra opción, más cerca de su código:

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

Esto evita la anidación tan profundamente (haciendo una salida temprana si la secuencia está vacía) y se utiliza un "real", mientras que la condición en lugar de while(true)

Otros consejos

Su aplicación se ve perfectamente bien para mí -. Es probable que sea la forma en que lo haría

El único que podría sugerir la simplificación en relación con su situación es ordenar la lista al revés (es decir, en lugar de ascendente descendente). Aunque esto puede no ser adecuado en su código, que sería permite utilizar simplemente collection.Skip(1) tomar todos los elementos excepto el más reciente.

Si esto no es posible por razones que no han mostrado en su puesto, entonces su implementación actual no es ningún problema en absoluto.

Si está utilizando .NET 3.5, supongo que se podría utilizar:

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

(respuesta vieja desechó;. Este código ha sido probado y funciona) Imprime
primero
segundo
PRIMERA
SEGUNDO
TERCER


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);
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top