Eu sei que poderia usar uma for
instrução e obter o mesmo efeito, mas posso fazer um loop para trás através de um foreach
loop em c #?
IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }
Como você reverteria isso?
Eu sei que poderia usar uma for
instrução e obter o mesmo efeito, mas posso fazer um loop para trás através de um foreach
loop em c #?
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 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 foreach
para loop.
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 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:
static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
return new Stack<T>(input);
}
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.
Como 280Z28 diz, para um IList<T>
você pode apenas usar o índice. Você pode ocultar 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];
}
}
Isso será mais rápido do Enumerable.Reverse()
que o buffer de todos os dados primeiro. (Não acredito que Reverse
tenham 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:
public static IEnumerable<T> GetStringsOfIncreasingSize()
{
string ret = "";
while (true)
{
yield return ret;
ret = ret + "x";
}
}
O que você esperaria que acontecesse se tentasse repetir isso inversamente?
Antes de usar foreach
para iteração, inverta a lista pelo reverse
método:
myList.Reverse();
foreach( List listItem in myList)
{
Console.WriteLine(listItem);
}
myList
é será útil. IEnumerable.Reverse não funcionará aqui.
myList
parece ser do tipo System.Collections.Generic.List<System.Windows.Documents.List>
(ou qualquer outro List
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;
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 "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.
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"
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
Se você usa uma lista <T>, 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 grava a lista em si mesma.
Agora o foreach:
foreach(string s in list)
{
Console.WriteLine(s);
}
A saída é:
3
2
1
É 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):
public IEnumerator<TObject> GetEnumerator()
{
for (var i = items.Count - 1; i >= 0; i--)
{
yield return items[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
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).
Não. O ForEach apenas percorre a coleção para cada item e o pedido depende se ele usa IEnumerable ou GetEnumerator ().
Ao elaborar com leveza a bela resposta de Jon Skeet , isso pode 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 então use como
foreach (var item in myList.Directional(forwardsCondition)) {
.
.
}
Eu usei esse código que funcionou
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) {
.Reverse()
está realmente modificando a lista.
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]);
}