Pergunta

Alguém sabe se houve um motivo específico ou uma decisão de design para não incluir um enumerador reverso em C #?Seria tão bom se houvesse um equivalente ao reverse_iterator C ++, assim como Enumerator é o equivalente ao iterator C ++.Coleções que podem ter iteração reversa apenas implementariam algo como IReverseEnumerable e alguém poderia fazer algo como:

List<int>.ReverseEnumerator ritr = collection.GetReverseEnumerator();
while(rtir.MoveNext())
{
 // do stuff
}

Dessa forma, você seria capaz de iterar listas e listas vinculadas da mesma maneira, em vez de usar indexador para um e links anteriores para o outro, obtendo assim uma melhor abstração

Foi útil?

Solução

Seria perfeitamente possível implementar isso. Pessoalmente, quase nunca faço a iteração reversa. Se eu precisar fazer isso, chamo .Reverse () primeiro. Provavelmente foi isso que os designers do .NET BCL também pensaram.

Todos os recursos não são implementados por padrão. Eles precisam ser projetados, implementados, testados, documentados e suportados. - Raymond Chen

E é por isso que você não implementa recursos que fornecem pouca utilidade. Você começa com os recursos mais importantes (como iterar de frente para trás). E você pára em algum lugar onde seu orçamento está esgotado ou onde você acha que não faz sentido continuar.

Existem muitas coisas que não estão na biblioteca de classes base .NET. Até o .NET 4 não havia nem File.EnumerateLines. E eu me arrisco a dizer que essa funcionalidade é mais importante do que a iteração reversa para a maioria das pessoas.

Pode ser o caso de você estar trabalhando em um domínio de negócios onde a iteração reversa é comum. Minha experiência é o oposto. Como designer de estrutura, você só pode adivinhar quem usará sua estrutura e quais recursos essas pessoas exigirão. É difícil traçar o limite.

Outras dicas

Não está disponível porque IEnumerable é um iterador somente de encaminhamento. Ele só tem um método MoveNext (). Isso torna a interface muito universal e o núcleo do Linq. Existem muitas coleções do mundo real que não podem ser iteradas de trás para frente porque isso requer armazenamento . A maioria dos streams são assim, por exemplo.

O Linq fornece uma solução com o método de extensão Reverse (). Ele funciona armazenando os elementos primeiro e, em seguida, iterando-os de trás para frente. Isso, entretanto, pode ser um grande desperdício, pois requer armazenamento O (n). Está faltando uma possível otimização para coleções já indexáveis. Que você pode consertar:

static class Extensions {
    public static IEnumerable<T> ReverseEx<T>(this IEnumerable<T> coll) {
        var quick = coll as IList<T>;
        if (quick == null) {
            foreach (T item in coll.Reverse()) yield return item;
        }
        else {
            for (int ix = quick.Count - 1; ix >= 0; --ix) {
                yield return quick[ix];
            }
        }
    }
}

Amostra de uso:

        var list = new List<int> { 0, 1, 2, 3 };
        foreach (var item in list.ReverseEx()) {
            Console.WriteLine(item);
        }

Você desejará fazer uma especialização para LinkedList, pois ele não implementa IList <>, mas ainda permite a iteração rápida para trás por meio das propriedades Last e LinkedListNode.Previous. Embora seja muito melhor não usar essa classe, ela tem uma péssima localização de cache de CPU. Sempre dê preferência a List <> quando não precisar de pastilhas baratas. Pode ser assim:

    public static IEnumerable<T> ReverseEx<T>(this LinkedList<T> list) {
        var node = list.Last;
        while (node != null) {
            yield return node.Value;
            node = node.Previous;
        }
    }

A dica está na linha final do OP: usando isso em Lists e LinkedLists.

Então, para um List, este funcionaria bem:

    public static IEnumerable<T> AsReverseEnumerator<T>(this IReadOnlyList<T> list)
    {
        for (int i = list.Count; --i >= 0;) yield return list[i];
    }

Usar IReadOnlyList oferece muita flexibilidade em termos de como ele funcionará.

Algo semelhante seria possível para LinkedLists.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top