Pergunta

Eu precisava de um método para me todos, mas o último item dar em uma seqüência. Esta é a minha implementação atual:

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

O que eu preciso dele para é fazer algo com todos os itens, exceto a última. No meu caso eu tenho uma seqüência de objetos com várias propriedades. Eu então encomendá-los por data, e, em seguida, eu preciso fazer um ajuste para todos eles, exceto o item mais recente (o que seria o último após a encomenda).

A coisa é, eu não sou muito para essas recenseadores e outras coisas ainda e realmente não tem ninguém aqui para pedir qualquer um: p O que eu estou querendo saber é se esta é uma boa implementação, ou se eu fiz uma pequena ou grande errar em algum lugar. Ou se talvez esta visão sobre o problema é uma estranha, etc.

Eu acho que uma aplicação mais geral poderia ter sido um método AllExceptMaxBy. Desde que é uma espécie do que é. A MoreLINQ tem uma MaxBy e método MinBy e meu método de tipo de necessidade de fazer o mesmo, mas devolver todos os itens, exceto o máximo ou mínimo um.

Foi útil?

Solução

Isto é complicado, como "último elemento" não é um ponto de parada Markov: você não pode dizer que você tem que o último elemento até que você tentar obter o próximo. É factível, mas apenas se você não se importa permanentemente ser "um elemento por trás". Isso é basicamente o que a sua implementação atual faz, e ele parece bem, embora eu provavelmente escrevê-lo de forma ligeiramente diferente.

Uma abordagem alternativa seria usar foreach, sempre produzindo o valor previamente retornado a menos que você estava na primeira iteração:

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

Outra opção, mais perto de seu 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;
        }
    }
}

Isso evita nidificação tão profundamente (fazendo uma saída precoce se a sequência estiver vazia) e ele usa um "real", enquanto condição em vez de while(true)

Outras dicas

sua implementação parece perfeitamente bem para mim. - É provavelmente a maneira que eu iria fazê-lo

A única simplificação eu poderia sugerir em relação à sua situação é para ordenar a lista o contrário (ou seja ascendente, em vez de descer). Embora isso possa não ser adequado em seu código, seria permitir que você simplesmente usar collection.Skip(1) tomar todos os itens exceto o mais recente.

Se isto não for possível, por razões que não têm mostrado em seu post, então a sua implementação atual é nenhum problema em tudo.

Se você estiver usando o .NET 3.5, eu acho que você poderia usar:

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

(resposta Old desfeito;. Esse código foi testado e funciona) Imprime
primeiro
segunda
PRIMEIRO
SEGUNDA
TERCEIRO


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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top