Pergunta

Eu sei que eu poderia usar uma declaração for e conseguir o mesmo efeito, mas posso trás loop através de um loop foreach em C #?

Foi útil?

Solução

Ao trabalhar com uma lista (indexação direta), você não pode fazê-lo de forma tão eficiente quanto usar um loop for.

Editar: o que geralmente significa, quando você estiver pode para usar um loop for, é provável que o método correto para esta tarefa. Além disso, para, tanto quanto foreach é implementado em-fim, a própria construção é construído para a expressão de laçadas que são independentes dos índices de elemento e ordem de iteração, o que é particularmente importante em paralela programação . É minha opinião que iteração depender de ordem não deve usar foreach para looping.

Outras dicas

Se você estiver em .NET 3.5 você pode fazer isso:

IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())

Não é muito eficiente, pois tem que ir, basicamente, através do enumerador para a frente colocando tudo em uma pilha em seguida, aparece tudo de volta na ordem inversa.

Se você tem uma coleção directamente-indexável (por exemplo IList) você deve definitivamente usar um loop for vez.

Se você estiver em .NET 2.0 e não pode usar um loop for (ou seja, você só tem um IEnumerable), então você só vai ter que escrever sua própria função inversa. Isso deve funcionar:

static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
    return new Stack<T>(input);
}

Esta depende de alguns comportamentos que talvez não seja tão óbvio. Quando você passar em um IEnumerable para o construtor pilha ele vai interagir com ele e empurrar os itens na pilha. Quando você, em seguida, percorrer a pilha ele aparece as coisas de volta na ordem inversa.

Este eo .NET método de extensão 3,5 Reverse(), obviamente explodir se você alimentá-lo um IEnumerable que nunca pára de artigos de retorno.

Como 280Z28 diz, por um IList<T> você pode simplesmente usar o índice. Você poderia esconder isso em um método de extensão:

public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
    for (int i = items.Count-1; i >= 0; i--)
    {
        yield return items[i];
    }
}

Este será mais rápido do que Enumerable.Reverse() que buffers todos os dados em primeiro lugar. (Eu não acredito Reverse tem nenhum otimizações aplicadas da maneira que Count() faz.) Note que isto significa tamponamento que os dados são lidos completamente quando você começa a iteração, enquanto FastReverse vai "ver" as alterações feitas à lista, enquanto você iterar. (Ele também vai quebrar se você remover vários itens entre iterações.)

Para as sequências gerais, não há nenhuma maneira de iteração em sentido inverso - a sequência pode ser infinita, por exemplo:

public static IEnumerable<T> GetStringsOfIncreasingSize()
{
    string ret = "";
    while (true)
    {
        yield return ret;
        ret = ret + "x";
    }
}

O que você espera que aconteça se você tentou iterar que em sentido inverso?

Antes de usar 'foreach' para a iteração, reverter a lista pelo método 'reverso':

    myList.Reverse();
    foreach( List listItem in myList)
    {
       Console.WriteLine(listItem);
    }

Se você usar um List , você também pode usar este código:

List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();

Este é um método que escrever a lista reversa em si.

Agora, o foreach:

foreach(string s in list)
{
    Console.WriteLine(s);
}

A saída é:

3
2
1

Às vezes você não tem o luxo de indexação, ou talvez você queira reverter os resultados de uma consulta Linq, ou talvez você não quer modificar a coleção de origem, se algum destes são verdadeiras, Linq pode ajudar você.

método de extensão A Linq usando tipos anônimos com Linq Select para fornecer uma chave de classificação para Linq OrderByDescending;

    public static IEnumerable<T> Invert<T>(this IEnumerable<T> source)
    {
        var transform = source.Select(
            (o, i) => new
            {
                Index = i,
                Object = o
            });

        return transform.OrderByDescending(o => o.Index)
                        .Select(o => o.Object);
    }

Uso:

    var eable = new[]{ "a", "b", "c" };

    foreach(var o in eable.Invert())
    {
        Console.WriteLine(o);
    }

    // "c", "b", "a"

É nomeado "Invert", porque é sinônimo de "Reverse" e permite disambiguation com a implementação Lista reverso.

É possível reverter determinadas faixas de uma coleção muito, desde Int32.MinValue e Int32.MaxValue estão fora do alcance de qualquer tipo de índice coleção, podemos aproveitá-los para o processo de encomenda; se um índice elemento está abaixo da gama dada, é atribuído Int32.MaxValue de modo a que a sua ordem não muda quando se utiliza OrderByDescending, Int32.MinValue semelhante, elementos em um maior índice do que a gama dada, será designado, de modo que eles aparecem ao fim do processo de encomenda. Todos os elementos dentro da gama dada são atribuídos seu índice normal e são invertidas em conformidade.

    public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count)
    {
        var transform = source.Select(
            (o, i) => new
            {
                Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i,
                Object = o
            });

        return transform.OrderByDescending(o => o.Index)
                        .Select(o => o.Object);
    }

Uso:

    var eable = new[]{ "a", "b", "c", "d" };

    foreach(var o in eable.Invert(1, 2))
    {
        Console.WriteLine(o);
    }

    // "a", "c", "b", "d"

Eu não tenho certeza dos hits dessas implementações Linq em vez de utilizar uma lista temporária para embrulhar uma coleção para reverter desempenho.


No momento da escrita, eu não estava ciente da própria implementação reverso do Linq, ainda assim, foi divertido trabalhar isso. https://msdn.microsoft.com/ en-us / library / VStudio / bb358497 (v = vs.100) .aspx

No. ForEach apenas itera por meio de coleta para cada item e ordem depende se ele usa IEnumerable ou GetEnumerator ().

É possível se você pode alterar o código de coleção que implementa IEnumerable ou IEnumerable (por exemplo sua própria implementação de IList).

Criar um Iterator fazer este trabalho para você, por exemplo, como a seguinte implementação através do IEnumerable de interface (assumindo que 'itens' é um campo de lista neste exemplo):

public IEnumerator<TObject> GetEnumerator()
{
    for (var i = items.Count - 1; i >= 0; i--)
    { 
        yield return items[i];
    }
}

IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

Por causa desta sua lista irá iterar em ordem inversa através de sua lista.

Apenas uma dica:. Você deve indicar claramente esse comportamento especial de sua lista dentro da documentação (ainda melhor, escolhendo um nome de classe de auto-explicando como Stack ou Fila, também)

Elaborateling slighty sobre a resposta agradável por Jon Skeet , isso poderia ser versátil:

public static IEnumerable<T> Directional<T>(this IList<T> items, bool Forwards) {
    if (Forwards) foreach (T item in items) yield return item;
    else for (int i = items.Count-1; 0<=i; i--) yield return items[i];
}

E, em seguida, usar como

foreach (var item in myList.Directional(forwardsCondition)) {
    .
    .
}

Eu tenho usado este código que trabalhou

                if (element.HasAttributes) {

                    foreach(var attr in element.Attributes().Reverse())
                    {

                        if (depth > 1)
                        {
                            elements_upper_hierarchy_text = "";
                            foreach (var ancest  in element.Ancestors().Reverse())
                            {
                                elements_upper_hierarchy_text += ancest.Name + "_";
                            }// foreach(var ancest  in element.Ancestors())

                        }//if (depth > 1)
                        xml_taglist_report += " " + depth  + " " + elements_upper_hierarchy_text+ element.Name + "_" + attr.Name +"(" + attr.Name +")" + "   =   " + attr.Value + "\r\n";
                    }// foreach(var attr in element.Attributes().Reverse())

                }// if (element.HasAttributes) {

Isso funciona muito bem

List<string> list = new List<string>();

list.Add("Hello");
list.Add("Who");
list.Add("Are");
list.Add("You");

foreach (String s in list)
{
    Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top