Eu escrevi isto:
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> obj, T value)
{
return obj
.Select((a, i) => (a.Equals(value)) ? i : -1)
.Max();
}
public static int IndexOf<T>(this IEnumerable<T> obj, T value
, IEqualityComparer<T> comparer)
{
return obj
.Select((a, i) => (comparer.Equals(a, value)) ? i : -1)
.Max();
}
}
Mas não sei se já existe, existe?
Max
abordagem é que um: ele continua olhando, e b: ele retorna o último índice quando houver duplicatas (as pessoas geralmente esperam que o primeiro índice)ToList()/FindIndex()
truque tem melhor desempenhoRespostas:
O objetivo de divulgar como IEnumerable é que você pode repetir preguiçosamente o conteúdo. Como tal, não existe realmente um conceito de índice. O que você está fazendo realmente não faz muito sentido para um IEnumerable. Se você precisar de algo que suporte o acesso por índice, coloque-o em uma lista ou coleção real.
fonte
IEnumerable<>
. Eu não compro todo o dogma "você deveria estar fazendo isso".IEnumerable
,Enumerable.ElementAt
não existiria.IndexOf
é simplesmente o inverso - qualquer argumento contra ele deve ser aplicado igualmente aElementAt
.Eu questionaria a sabedoria, mas talvez:
(usando
EqualityComparer<T>.Default
para emular,!=
se necessário) - mas você precisa prestar atenção para retornar -1 se não for encontrado ... então, talvez faça o caminho mais longofonte
TakeWhile
é esperto! Tenha em mente que isso retornaCount
se o elemento não existir, que é um desvio do comportamento padrão.Eu implementaria assim:
fonte
==
pode precisar de trabalho?KVP<T, int?>
(índice nulo)IList<T>
e, se for o caso, adie para o método IndexOf apenas no caso de uma otimização específica do tipo.A maneira como estou fazendo isso atualmente é um pouco menor do que os já sugeridos e, até onde sei, dá o resultado desejado:
É um pouco desajeitado, mas faz o trabalho e é bastante conciso.
fonte
A melhor maneira de capturar a posição é por
FindIndex
Esta função está disponível apenas paraList<>
Exemplo
Se você tiver um enumerador ou matriz, use desta maneira
ou
fonte
Eu acho que a melhor opção é implementar assim:
Também não criará o objeto anônimo
fonte
Um pouco tarde no jogo, eu sei ... mas foi isso que fiz recentemente. É um pouco diferente do seu, mas permite que o programador determine o que a operação de igualdade precisa ser (predicado). O que acho muito útil ao lidar com tipos diferentes, pois tenho uma maneira genérica de fazê-lo, independentemente do tipo de objeto e
<T>
operador de igualdade incorporado.Ele também tem uma pegada de memória muito pequena e é muito, muito rápido / eficiente ... se você se importa com isso.
Na pior das hipóteses, basta adicionar isso à sua lista de extensões.
Enfim ... aqui está.
Espero que isso ajude alguém.
fonte
GetEnumerator
eMoveNext
ao invés de apenas umforeach
?foreach
chamaráDispose
o enumerador se ele implementarIDisposable
. (Consulte stackoverflow.com/questions/4982396/… ) Como o código nesta resposta não sabe se o resultado da chamadaGetEnumerator
é ou não descartável, ele deve fazer o mesmo. Naquele momento, ainda não estou claro se há um benefício de desempenho, embora houvesse alguma IL extra cujo objetivo não me ocorreu!foreach
loop; nesse caso, no caso particular deT
sendo um tipo de valor, pode estar salvando uma operação de caixa / unbox usando o loop while. No entanto, isso não é confirmado pelo IL que recebi de uma versão da sua respostaforeach
. Ainda acho que a disposição condicional do iterador é importante. Você poderia modificar a resposta para incluir isso?Alguns anos depois, mas isso usa o Linq, retorna -1 se não for encontrado, não cria objetos extras e deve causar um curto-circuito quando encontrado [em oposição à iteração em todo o IEnumerable]:
Onde 'FirstOr' é:
fonte
source.Where
esource.DefaultIfEmpty
criarão, por exemplo, umIEnumerable
cada.Tropecei hoje hoje em busca de respostas e pensei em adicionar minha versão à lista (sem trocadilhos). Ele utiliza o operador condicional nulo do c # 6.0
Eu fiz algumas corridas com cavalos velhos (testes) e para grandes coleções (~ 100.000), o pior cenário que o item desejado é no final, é duas vezes mais rápido do que fazer
ToList().FindIndex()
. Se o item que você quer está no meio, é ~ 4x mais rápido.Para coleções menores (~ 10.000), parece ser apenas um pouco mais rápido
Aqui está como eu testei https://gist.github.com/insulind/16310945247fcf13ba186a45734f254e
fonte
Usando a resposta de @Marc Gravell, encontrei uma maneira de usar o seguinte método:
para obter -1 quando o item não puder ser encontrado:
Eu acho que dessa maneira poderia ser o mais rápido e o mais simples. No entanto, ainda não testei performances.
fonte
Uma alternativa para localizar o índice após o fato é agrupar o Enumerable, um pouco semelhante ao uso do método Linq GroupBy ().
O que fornece um caso de uso de:
fonte
Isso pode ser muito legal com uma extensão (funcionando como proxy), por exemplo:
O que atribuirá automaticamente índices à coleção acessível por este
Index
propriedade.Interface:
Extensão personalizada (provavelmente mais útil para trabalhar com EF e DbContext):
fonte