Pergunta

Existe uma maneira melhor de fazer isso?

string[] s = {"zero", "one", "two", "three", "four", "five"};

var x = 
s
.Select((a,i) => new {Value = a, Index = i})
.Where(b => b.Value.StartsWith("t"))
.Select(c => c.Index);

i. Eu estou procurando uma maneira mais eficiente ou mais elegante para obter as posições dos itens que correspondam aos critérios.

Foi útil?

Solução

Você pode facilmente adicionar seu próprio método de extensão:

public static IEnumerable<int> IndexesWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    int index=0;
    foreach (T element in source)
    {
        if (predicate(element))
        {
            yield return index;
        }
        index++;
    }
}

Em seguida, usá-lo com:

string[] s = {"zero", "one", "two", "three", "four", "five"};
var x = s.IndexesWhere(t => t.StartsWith("t"));

Outras dicas

Se você está apenas usando o exemplo como uma maneira de aprender LINQ, ignore este post.


Não é claro para mim que LINQ é realmente a melhor maneira de fazer isso. O código a seguir parece que seria mais eficiente desde há novas necessidades tipo anônimo a ser criado. Concedido, o seu exemplo pode ser planejado e a técnica pode ser mais útil em um contexto diferente, por exemplo, em uma estrutura de dados onde poderia tirar proveito de um índice sobre o valor, mas o código abaixo é razoavelmente simples e direta, compreensível (sem pensamento necessário) e, possivelmente, mais eficiente.

string[] s = {"zero", "one", "two", "three", "four", "five"};
List<int> matchingIndices = new List<int>();

for (int i = 0; i < s.Length; ++i) 
{
   if (s[i].StartWith("t"))
   {
      matchingIndices.Add(i);
   }
}

Parece-me muito bem. Você pode salvar um casal caracteres, alterando a seleção para:

.Select((Value, Index) => new {Value, Index})

Há também método FindIndex na Lista da Colecção para o qual você cria um método de exclusão que pode retornar o índice da coleção. você pode consultar o seguinte link no MSDN http://msdn.microsoft.com /en-us/library/x1xzf2ca.aspx .

Como sobre isso? É semelhante ao do cartaz originais mas eu primeiro selecionar os índices e, em seguida, construir uma coleção que corresponde aos critérios.

var x = s.Select((a, i) => i).Where(i => s[i].StartsWith("t"));

Este é um pouco menos eficiente do que alguns dos outros respostas como a lista está totalmente iterada duas vezes.

Eu discuti esse problema interessante com um colega e no começo eu pensei que a solução da JonSkeet era grande, mas o meu colega apontou um problema, ou seja, que se a função é uma extensão para IEnumerable<T>, então ele pode ser usado onde uma coleção implementa .

Com uma variedade, é seguro dizer que a ordem produzida com foreach será respeitado (ie foreach vai iteração do primeiro ao último), mas não seria necessariamente o caso com outras coleções (Lista, dicionário, etc.), onde foreach não refletiria necessariamente "ordem de entrada". No entanto, a função está lá, e ele pode ser enganosa.

No final, eu acabei com algo semelhante a resposta de tvanfosson, mas como um método de extensão, para matrizes:

public static int[] GetIndexes<T>(this T[]source, Func<T, bool> predicate)
{
    List<int> matchingIndexes = new List<int>();

    for (int i = 0; i < source.Length; ++i) 
    {
        if (predicate(source[i]))
        {
            matchingIndexes.Add(i);
        }
    }
    return matchingIndexes.ToArray();
}

Aqui está esperando List.ToArray vai respeitar a ordem para a última operação ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top