Verifique se a lista <t> contém qualquer outra lista

93

Tenho uma lista de parâmetros como esta:

public class parameter
{
    public string name {get; set;}
    public string paramtype {get; set;}
    public string source {get; set;}
}

IEnumerable<Parameter> parameters;

E uma série de strings que eu quero comparar.

string[] myStrings = new string[] { "one", "two"};

Desejo iterar a lista de parâmetros e verificar se a propriedade source é igual a alguma da matriz myStrings. Eu posso fazer isso com foreach's aninhados, mas gostaria de aprender como fazê-lo de uma maneira mais agradável, já que tenho brincado com o linq e gosto dos métodos de extensão em enumeráveis ​​como where etc, então foreachs aninhados parece errado. Existe uma maneira linq / lambda / delegete mais elegante de fazer isso.

obrigado

gdp
fonte

Respostas:

196

Você pode usar um aninhado Any()para esta verificação que está disponível em qualquer Enumerable:

bool hasMatch = myStrings.Any(x => parameters.Any(y => y.source == x));

Faster realizando em coleções maiores seria projecto parameterspara sourcee, em seguida, usar Intersectque usa internamente um HashSet<T>assim em vez de O (n ^ 2) para a primeira abordagem (o equivalente a dois loops aninhados) você pode fazer o check-in O (n):

bool hasMatch = parameters.Select(x => x.source)
                          .Intersect(myStrings)
                          .Any(); 

Além disso, como comentário lateral, você deve colocar os nomes das classes e das propriedades em letras maiúsculas para estar de acordo com as diretrizes de estilo C #.

Vidro quebrado
fonte
obrigado parece ser o que estou procurando, vou experimentá-lo. Precisa brincar um pouco mais com o lado funcional das coisas. em relação a capitalizar classe e propriedades, eu simplesmente fui esquecido quando escrevi o exemplo acima.
gdp
1
Por que O (n ^ 2)? Não é O (n * m), já que estamos falando sobre duas variáveis ​​e não uma? Como m (os parâmetros) são constantes, é o mesmo que O (n). Não vejo como a intersecção deveria ser muito mais rápida aqui. Mas combinado, o Intersect tem potencial para ser mais rápido, mas não é garantido.
Squazz de
Você está certo que deveria ser O (n * m) - m não é uma constante - é do tamanho de uma das listas, mesmo que no exemplo particular dado possa ser "2". Mesmo os valores constantes não são desprezíveis na prática - para todos os comprimentos de lista não triviais Intersect, será mais rápido - se as listas forem trivialmente curtas, não importa de uma forma ou de outra (nesse caso, o desempenho provavelmente não é sua preocupação de qualquer maneira )
BrokenGlass de
como você pode descobrir o índice da lista onde a condição se torna verdadeira? Eu tenho uma lista com frases. Eu tenho uma matriz com palavras específicas. Quero os índices da lista se a frase tiver pelo menos uma palavra da matriz. @BrokenGlass
kirushan
1
Em termos de desempenho, não parameters.Any(x => myStrings.Contains(x.source));seria melhor do que seu primeiro exemplo?
Fluppe de
3

Aqui está um exemplo para descobrir se há elementos correspondentes em outra lista

List<int> nums1 = new List<int> { 2, 4, 6, 8, 10 };
List<int> nums2 = new List<int> { 1, 3, 6, 9, 12};

if (nums1.Any(x => nums2.Any(y => y == x)))
{
    Console.WriteLine("There are equal elements");
}
else
{
    Console.WriteLine("No Match Found!");
}
Masoud Darvishian
fonte
2
Observe que se as listas envolvidas forem grandes, isso vai acabar sendo muito mais lento do que a Intersectabordagem, pois é O (N * M) nos tamanhos das listas. (É O (1) na memória embora.)
Jon Skeet
1

Se ambas as listas forem muito grandes e quando usarmos a expressão lamda, a busca demorará muito. Melhor usar o linq neste caso para buscar a lista de parâmetros:

var items = (from x in parameters
                join y in myStrings on x.Source equals y
                select x)
            .ToList();
Umang Agarwal
fonte