Eu tenho um foreach
loop e preciso executar alguma lógica quando o último item for escolhido List
, por exemplo:
foreach (Item result in Model.Results)
{
//if current result is the last item in Model.Results
//then do something in the code
}
Posso saber qual loop é o último sem usar loop e contadores?
Respostas:
Se você apenas precisar fazer algo com o último elemento (em oposição a algo diferente com o último elemento, o uso do LINQ ajudará aqui:
Se você precisar fazer algo diferente com o último elemento, precisará de algo como:
Embora você provavelmente precise escrever um comparador personalizado para garantir que você possa dizer que o item é igual ao item retornado por
Last()
.Essa abordagem deve ser usada com cautela, pois
Last
pode ser necessário percorrer a coleção. Embora isso possa não ser um problema para coleções pequenas, se ficar grande, poderá ter implicações no desempenho. Também falhará se a lista contiver itens duplicados. Nesse caso, algo como isto pode ser mais apropriado:fonte
var last = Model.Result[Model.Result.Count - 1];
para uma mais rápida do que usandoLast()
Que tal um bom loop antiquado para?
Ou usando o Linq e o foreach:
fonte
Model.Results
for umIEnumerable
. Você pode chamarCount()
antes do loop, mas isso pode causar a iteração completa da sequência.O uso
Last()
de certos tipos percorrerá toda a coleção!Significando que, se você fizer uma
foreach
chamada e fizer umLast()
loop duas vezes! o que tenho certeza que você gostaria de evitar em grandes coleções.Então a solução é usar um
do while
loop:Portanto, a menos que o tipo de coleção seja do tipo,
IList<T>
aLast()
função irá percorrer todos os elementos da coleção.Teste
Se sua coleção fornece acesso aleatório (por exemplo, implementos
IList<T>
), você também pode verificar seu item da seguinte maneira.fonte
using
declaração? Eu pensei que isso seria necessário apenas se um objeto manipular recursos do sistema operacional, mas não para estruturas de dados gerenciadas.Como Chris mostra, Linq funcionará; basta usar Last () para obter uma referência à última no enumerável e, desde que você não esteja trabalhando com essa referência, faça seu código normal, mas se você estiver trabalhando com essa referência, faça seu trabalho extra. Sua desvantagem é que sempre haverá complexidade O (N).
Em vez disso, você pode usar Count () (que é O (1) se o IEnumerable também for um ICollection; isso é verdade para a maioria dos IEnumerables internos comuns) e híbrir sua foreach com um contador:
fonte
fonte
foreach
bloco. Como esta:var lastItem = objList.LastOrDeafault();
. Em seguida, a partir do interior deforeach
loop que você pode verificá-lo desta forma:f (item.Equals(lastItem)) { ... }
. Na sua resposta original, aobjList.LastOrDefault()
iteração seria feita sobre a coleção em cada iteração "foreach" ( complexidade polinomial está envolvida ).Como Shimmy apontou, usar Last () pode ser um problema de desempenho, por exemplo, se sua coleção é o resultado ao vivo de uma expressão LINQ. Para evitar várias iterações, você pode usar um método de extensão "ForEach" como este:
O método de extensão é parecido com este (como um bônus adicional, ele também informa o índice e se você está vendo o primeiro elemento):
fonte
Melhorando ainda mais a resposta de Daniel Wolf, você pode empilhar outra
IEnumerable
para evitar várias iterações e lambdas, como:A implementação do método de extensão:
fonte
foreach
, o que é uma melhoria.A implementação do iterador não fornece isso. Sua coleção pode ser
IList
acessível através de um índice em O (1). Nesse caso, você pode usar umfor
loop normal :Se você conhece a contagem, mas não pode acessar por meio de índices (portanto, o resultado é um
ICollection
), pode contar-se incrementando umi
noforeach
corpo do e comparando-o com o comprimento.Tudo isso não é perfeitamente elegante. A solução de Chris pode ser a mais bonita que eu já vi até agora.
fonte
Que tal pouca abordagem mais simples.
fonte
A melhor abordagem provavelmente seria apenas executar essa etapa após o loop: por exemplo
Ou se você precisar fazer algo até o último resultado
fonte
A resposta aceita não funcionará para duplicatas na coleção. Se você estiver definido como
foreach
, basta adicionar suas próprias variáveis de indexação.fonte
usando o Linq e o foreach:
https://code.i-harness.com/en/q/7213ce
fonte
".Last ()" não funcionou para mim, então eu tive que fazer algo assim:
fonte
Fazendo alguns pequenos ajustes no excelente código de Jon Skeet, você pode até torná-lo mais inteligente, permitindo o acesso ao item anterior e ao próximo. Obviamente, isso significa que você terá que ler um item à frente na implementação. Por motivos de desempenho, o item anterior e o próximo são retidos apenas para o item de iteração atual. É assim:
fonte
Como converter
foreach
para reagir ao último elemento:fonte
Apenas armazene o valor anterior e trabalhe com ele dentro do loop. Então, no final, o valor 'anterior' será o último item, permitindo que você o manipule de maneira diferente. Nenhuma biblioteca especial ou de contagem é necessária.
fonte
Você pode usar um loop for e não há necessidade de adicionar um extra
if
dentro dofor
corpo:A
-1
nafor
condição cuida de pular o último item.fonte
Jon Skeet criou um
SmartEnumerable<T>
tipo há algum tempo para resolver esse problema exato. Você pode ver sua implementação aqui:http://codeblog.jonskeet.uk/2007/07/27/smart-enumerations/
Para fazer o download: http://www.yoda.arachsys.com/csharp/miscutil/
fonte
Para fazer algo adicional a cada elemento, exceto o último, a abordagem baseada em funções pode ser usada.
Essa abordagem tem desvantagens aparentes: menos clareza de código para casos mais complexos. Ligar para os delegados pode não ser muito eficaz. A solução de problemas pode não ser muito fácil. O lado positivo - a codificação é divertida!
Dito isto, sugiro o uso de plain para loops em casos triviais, se você souber que a contagem de sua coleção não é muito lenta.
fonte
Outra maneira, que eu não vi postada, é usar uma Fila. É análogo a uma maneira de implementar um método SkipLast () sem repetir mais do que o necessário. Dessa forma, você também poderá fazer isso em qualquer número de últimos itens.
Para chamar isso, faça o seguinte:
fonte
fonte
Você pode criar um método de extensão especialmente dedicado a isso:
e você pode usá-lo assim:
fonte
Com base na resposta de @ Shimmy, criei um método de extensão que é a solução que todos desejam. É simples, fácil de usar e apenas percorre a coleção uma vez.
Isso funciona em qualquer
IEnumerable<T>
. O uso fica assim:A saída se parece com:
Além disso, você pode transformar isso em um
Select
método de estilo. Em seguida, reutilize essa extensão noForEach
. Esse código fica assim:fonte
Podemos verificar o último item em loop.
fonte
fonte
Você pode fazer assim:
fonte