Você precisaria instanciar todos os elementos na enumeração para poder reverter a ordem deles. Pode não ser possível. Considere a sequência: IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }Como você reverteria isso?
Suncat2000 30/01
Respostas:
84
Ao trabalhar com uma lista (indexação direta), você não pode fazê-lo tão eficientemente quanto usar um forloop.
Editar: o que geralmente significa que, quando você é capaz de usar um forloop, é provavelmente o método correto para esta tarefa. Além disso, na medida em que foreaché implementado em ordem, o próprio construto é construído para expressar loops independentes dos índices de elementos e da ordem de iteração, o que é particularmente importante na programação paralela . É minha opinião que a iteração que depende de ordem não deve ser usada foreachpara loop.
Acho sua última afirmação um pouco genérica demais. Certamente há casos em que, por exemplo, um IEnumerable de algum tipo precisa ser iterado em ordem? Você não usaria foreach nesse caso? O que você usaria?
precisa saber é
1
ATUALIZAÇÃO: Consulte [A resposta de Bryan para uma pergunta semelhante [( stackoverflow.com/a/3320924/199364 )), para obter uma resposta mais moderna, usando o Linq, e discutindo as duas listas e outros enumeráveis.
Home
ATUALIZAÇÃO: Jon Skeet tem uma resposta ainda mais elegante, que agora é possível, usando " yield return".
Home
2
Tive a mesma reação inicial que @avl_sweden - "a iteração que depende da ordem não deve usar foreach" soa muito ampla. Sim, o foreach é bom para expressar tarefas paralelas independentes de ordem. MAS também é uma parte essencial da programação moderna baseada em iterador . Talvez o ponto seja que seria mais claro / seguro se houvesse duas palavras-chave distintas , para esclarecer se alguém está afirmando que as iterações são independentes de ordem? [Dada uma linguagem como Eiffel que podem propagar contratos, tais afirmações poderiam ser comprovadamente verdadeiro ou falso, para determinado código.]
ToolmakerSteve
2
A ideia de que foreach "é criada para expressar loops independentes de índices de elementos e ordem de iteração" está incorreta. A especificação da linguagem c # requer que cada elemento do processo esteja em ordem. Usando MoveNext em iteradores ou processando índices começando em zero e incrementando em um em cada iteração de matrizes.
Donald Rich
145
Se você estiver no .NET 3.5, poderá fazer o seguinte:
IEnumerable<int> enumerableThing =...;foreach(var x in enumerableThing.Reverse())
Não é muito eficiente, pois precisa passar basicamente pelo enumerador, colocando tudo em uma pilha e exibindo tudo de volta na ordem inversa.
Se você tem uma coleção indexável diretamente (por exemplo, IList), definitivamente deve usar um forloop.
Se você está no .NET 2.0 e não pode usar um loop for (ou seja, você apenas possui um IEnumerable), basta escrever sua própria função Reverse. Isso deve funcionar:
Isso depende de algum comportamento que talvez não seja tão óbvio. Quando você passa um IEnumerable para o construtor de pilha, ele percorre e empurra os itens para a pilha. Quando você percorre a pilha, as coisas retornam na ordem inversa.
Esse Reverse()método de extensão .NET 3.5 obviamente explodirá se você alimentar um IEnumerable que nunca interrompa o retorno de itens.
Também esqueci de mencionar .net v2 apenas por favor
JL.
4
Solução .NET 2.0 interessante.
31410 RichardOD
11
Estou faltando alguma coisa ou a sua solução .Net 3.5 não funciona realmente? Reverse () inverte a lista no local e não a retorna. Pena que eu esperava uma solução como essa.
@ user12861, Micky Duncan: a resposta não está errada, está faltando alguma coisa. Há um método Reverse em System.Collections.Generic.List <T> que faz um inverso no local. No .Net 3.5, existe um método de extensão no IEnumerable <T> chamado Reverse. Alterei o exemplo de var para IEnumerable <int> para tornar isso mais explícito.
precisa
55
Como 280Z28 diz, para um IList<T>você pode apenas usar o índice. Você pode ocultar isso em um método de extensão:
publicstaticIEnumerable<T>FastReverse<T>(thisIList<T> items){for(int i = items.Count-1; i >=0; i--){yieldreturn items[i];}}
Isso será mais rápido do Enumerable.Reverse()que o buffer de todos os dados primeiro. (Não acredito que Reversetenham sido aplicadas otimizações dessa maneira Count().) Observe que esse buffer significa que os dados são lidos completamente quando você inicia a iteração, enquantoFastReverse "verá" as alterações feitas na lista durante a iteração. (Ele também será interrompido se você remover vários itens entre as iterações.)
Para seqüências gerais, não há como iterar ao contrário - a sequência pode ser infinita, por exemplo:
publicstaticIEnumerable<T>GetStringsOfIncreasingSize(){string ret ="";while(true){yieldreturn ret;
ret = ret +"x";}}
O que você esperaria que acontecesse se tentasse repetir isso inversamente?
Apenas curiosidade, por que usar "> = 0" em vez de "> -1"?
Chris S
15
> por que usar "> = 0" em vez de "> -1"? Porque> = 0 comunica melhor a intenção aos humanos que leem o código. O compilador deve poder otimizar isso para o equivalente a -1, se isso melhorar o desempenho.
27230 Mark Maslar
1
FastReverse (este IList <T> itens) deve ser FastReverse <T> (este IList <T> itens :).
Rob
Dividir varas 0 <= i é ainda melhor. Depois de ensinar um monte de matemática para crianças ao longo dos anos e ajudar as pessoas com a codificação, descobri que isso reduz muito os erros que as pessoas cometem se SEMPRE trocarem a> b para b <a, pois as coisas vêm na ordem natural de uma linha de números (ou o eixo X de um sistema de coordenadas) - o único inconveniente é se você precisa colar uma equação em XML, digamos, um .config
Eske Rahn
13
Antes de usar foreachpara iteração, inverta a lista pelo reversemétodo:
myList.Reverse();foreach(List listItem in myList){Console.WriteLine(listItem);}
Uma palavra de cautela sobre o que myListé será útil. IEnumerable.Reverse não funcionará aqui.
Nawfal # 26/18
2
@ MA-Maddin não, os dois são diferentes. Eu acho que o respondente está contando com a lista <T> .Reverse, que está no lugar.
Nawfal
Na verdade, não sei por que disse isso. Eu deveria ter adicionado mais detalhes ... De qualquer forma, esse código é confuso, pois myListparece ser do tipo System.Collections.Generic.List<System.Windows.Documents.List>(ou qualquer outro Listtipo personalizado ), caso contrário, esse código não funciona: P
Martin Schneider
5
Às vezes, você não tem o luxo de indexar, ou talvez queira reverter os resultados de uma consulta do Linq, ou talvez não queira modificar a coleção de fontes, se alguma for verdadeira, o Linq pode ajudá-lo.
Um método de extensão Linq usando tipos anônimos com Linq Select para fornecer uma chave de classificação para Linq OrderByDescending;
var eable =new[]{"a","b","c"};foreach(var o in eable.Invert()){Console.WriteLine(o);}// "c", "b", "a"
É nomeado "Inverter" porque é sinônimo de "Reverso" e permite a desambiguação com a implementação de Reversão de Lista.
Também é possível reverter certos intervalos de uma coleção, já que Int32.MinValue e Int32.MaxValue estão fora do intervalo de qualquer tipo de índice de coleção, podemos aproveitá-los para o processo de pedido; se um índice de elemento estiver abaixo do intervalo especificado, ele será designado Int32.MaxValue para que sua ordem não seja alterada ao usar OrderByDescending; da mesma forma, os elementos em um índice maior que o intervalo especificado serão atribuídos Int32.MinValue, para que eles aparecem até o final do processo de pedido. Todos os elementos dentro do intervalo determinado recebem seu índice normal e são revertidos de acordo.
publicstaticIEnumerable<T>Invert<T>(thisIEnumerable<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"
Não tenho certeza dos resultados de desempenho dessas implementações do Linq versus o uso de uma lista temporária para agrupar uma coleção para reversão.
É possível se você pode alterar o código da coleção que implementa IEnumerable ou IEnumerable (por exemplo, sua própria implementação do IList).
Crie um iterador fazendo esse trabalho para você, por exemplo, como a seguinte implementação por meio da interface IEnumerable (supondo que 'itens' seja um campo Lista neste exemplo):
publicIEnumerator<TObject>GetEnumerator(){for(var i = items.Count-1; i >=0; i--){yieldreturn items[i];}}IEnumeratorIEnumerable.GetEnumerator(){returnGetEnumerator();}
Por esse motivo, sua Lista irá repetir a ordem inversa na sua lista.
Apenas uma dica: você deve indicar claramente esse comportamento especial da sua lista na documentação (melhor ainda, escolhendo um nome de classe autoexplicativo, como Pilha ou Fila, também).
Isso é ruim porque .Reverse()está realmente modificando a lista.
Colin Basnett
-8
Isso funciona muito bem
List<string>list=newList<string>();list.Add("Hello");list.Add("Who");list.Add("Are");list.Add("You");foreach(String s inlist){Console.WriteLine(list[list.Count-list.IndexOf(s)-1]);}
IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }
Como você reverteria isso?Respostas:
Ao trabalhar com uma lista (indexação direta), você não pode fazê-lo tão eficientemente quanto usar um
for
loop.Editar: o que geralmente significa que, quando você é capaz de usar um
for
loop, é provavelmente o método correto para esta tarefa. Além disso, na medida em queforeach
é implementado em ordem, o próprio construto é construído para expressar loops independentes dos índices de elementos e da ordem de iteração, o que é particularmente importante na programação paralela . É minha opinião que a iteração que depende de ordem não deve ser usadaforeach
para loop.fonte
yield return
".Se você estiver no .NET 3.5, poderá fazer o seguinte:
Não é muito eficiente, pois precisa passar basicamente pelo enumerador, colocando tudo em uma pilha e exibindo tudo de volta na ordem inversa.
Se você tem uma coleção indexável diretamente (por exemplo, IList), definitivamente deve usar um
for
loop.Se você está no .NET 2.0 e não pode usar um loop for (ou seja, você apenas possui um IEnumerable), basta escrever sua própria função Reverse. Isso deve funcionar:
Isso depende de algum comportamento que talvez não seja tão óbvio. Quando você passa um IEnumerable para o construtor de pilha, ele percorre e empurra os itens para a pilha. Quando você percorre a pilha, as coisas retornam na ordem inversa.
Esse
Reverse()
método de extensão .NET 3.5 obviamente explodirá se você alimentar um IEnumerable que nunca interrompa o retorno de itens.fonte
Como 280Z28 diz, para um
IList<T>
você pode apenas usar o índice. Você pode ocultar isso em um método de extensão:Isso será mais rápido do
Enumerable.Reverse()
que o buffer de todos os dados primeiro. (Não acredito queReverse
tenham sido aplicadas otimizações dessa maneiraCount()
.) Observe que esse buffer significa que os dados são lidos completamente quando você inicia a iteração, enquantoFastReverse
"verá" as alterações feitas na lista durante a iteração. (Ele também será interrompido se você remover vários itens entre as iterações.)Para seqüências gerais, não há como iterar ao contrário - a sequência pode ser infinita, por exemplo:
O que você esperaria que acontecesse se tentasse repetir isso inversamente?
fonte
Antes de usar
foreach
para iteração, inverta a lista peloreverse
método:fonte
myList
é será útil. IEnumerable.Reverse não funcionará aqui.myList
parece ser do tipoSystem.Collections.Generic.List<System.Windows.Documents.List>
(ou qualquer outroList
tipo personalizado ), caso contrário, esse código não funciona: PÀs vezes, você não tem o luxo de indexar, ou talvez queira reverter os resultados de uma consulta do Linq, ou talvez não queira modificar a coleção de fontes, se alguma for verdadeira, o Linq pode ajudá-lo.
Um método de extensão Linq usando tipos anônimos com Linq Select para fornecer uma chave de classificação para Linq OrderByDescending;
Uso:
É nomeado "Inverter" porque é sinônimo de "Reverso" e permite a desambiguação com a implementação de Reversão de Lista.
Também é possível reverter certos intervalos de uma coleção, já que Int32.MinValue e Int32.MaxValue estão fora do intervalo de qualquer tipo de índice de coleção, podemos aproveitá-los para o processo de pedido; se um índice de elemento estiver abaixo do intervalo especificado, ele será designado Int32.MaxValue para que sua ordem não seja alterada ao usar OrderByDescending; da mesma forma, os elementos em um índice maior que o intervalo especificado serão atribuídos Int32.MinValue, para que eles aparecem até o final do processo de pedido. Todos os elementos dentro do intervalo determinado recebem seu índice normal e são revertidos de acordo.
Uso:
Não tenho certeza dos resultados de desempenho dessas implementações do Linq versus o uso de uma lista temporária para agrupar uma coleção para reversão.
No momento em que escrevi, eu não estava ciente da implementação reversa do Linq, ainda assim, foi divertido trabalhar com isso. https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx
fonte
Se você usa uma lista <T>, também pode usar este código:
Este é um método que grava a lista em si mesma.
Agora o foreach:
A saída é:
fonte
É possível se você pode alterar o código da coleção que implementa IEnumerable ou IEnumerable (por exemplo, sua própria implementação do IList).
Crie um iterador fazendo esse trabalho para você, por exemplo, como a seguinte implementação por meio da interface IEnumerable (supondo que 'itens' seja um campo Lista neste exemplo):
Por esse motivo, sua Lista irá repetir a ordem inversa na sua lista.
Apenas uma dica: você deve indicar claramente esse comportamento especial da sua lista na documentação (melhor ainda, escolhendo um nome de classe autoexplicativo, como Pilha ou Fila, também).
fonte
Não. O ForEach apenas percorre a coleção para cada item e o pedido depende se ele usa IEnumerable ou GetEnumerator ().
fonte
Ao elaborar com leveza a bela resposta de Jon Skeet , isso pode ser versátil:
E então use como
fonte
Eu usei esse código que funcionou
fonte
.Reverse()
está realmente modificando a lista.Isso funciona muito bem
fonte