Compruebe si list <t> contiene alguna otra lista

97

Tengo una lista de parámetros como este:

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

IEnumerable<Parameter> parameters;

Y una serie de cadenas con las que quiero compararlas.

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

Quiero iterar sobre la lista de parámetros y verificar si la propiedad fuente es igual a cualquiera de la matriz myStrings. Puedo hacer esto con foreach anidados, pero me gustaría aprender cómo hacerlo de una manera más agradable, ya que he estado jugando con linq y me gustan los métodos de extensión en enumerable, como dónde, etc., por lo que los foreachs anidados se sienten mal. ¿Hay una forma linq / lambda / delegete preferida más elegante de hacer esto?

Gracias

pib
fuente

Respuestas:

207

Puede usar un anidado Any()para esta verificación que está disponible en cualquier Enumerable:

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

Más rápido en la realización de las colecciones más grandes sería la de proyecto parameterspara sourcey luego usar Intersectla que internamente usa un HashSet<T>así que en vez de O (n ^ 2) para el primer enfoque (el equivalente a dos bucles anidados) que puede hacer el registro de entrada en O (n):

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

Además, como comentario lateral, debe escribir con mayúscula los nombres de sus clases y propiedades para cumplir con las pautas de estilo de C #.

Vidrio roto
fuente
gracias parece ser lo que estoy buscando lo probaré. Necesito jugar un poco más con el lado funcional de las cosas. con respecto a la capitalización de la clase y las propiedades, simplemente me olvidé cuando escribí el ejemplo anterior.
gdp
1
¿Por qué O (n ^ 2)? ¿No es O (n * m) como estamos hablando sobre dos variables y no una? Dado que m (los parámetros) son una constante, es lo mismo que O (n). No veo cómo la intersección debería ser mucho más rápida aquí. Pero de acuerdo, Intersect tiene el potencial de ser más rápido, pero no está garantizado.
Squazz
Tiene razón en que debería ser O (n * m) - aunque m no es una constante - es el tamaño de una de las listas, aunque en el ejemplo particular dado podría ser "2". Incluso los valores constantes, aunque no son despreciables en la práctica, para todas las longitudes de lista no triviales Intersect, será más rápido; si las listas son trivialmente cortas, no importa de una forma u otra (en ese caso, el rendimiento probablemente no sea su preocupación en absoluto de todos modos )
BrokenGlass
¿Cómo puedes averiguar el índice de la lista donde la condición se vuelve verdadera? Tengo una lista con frases. Tengo una matriz con palabras particulares. Quiero índices de la lista si la oración tiene al menos una palabra de la matriz. @BrokenGlass
kirushan
1
En cuanto al rendimiento, ¿no parameters.Any(x => myStrings.Contains(x.source));sería mejor que su primer ejemplo?
Fluppe
3

Aquí hay una muestra para encontrar si hay elementos coincidentes en otra 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
fuente
2
Tenga en cuenta que si las listas involucradas son grandes, esto terminará siendo mucho más lento que el Intersectenfoque, ya que es O (N * M) en los tamaños de las listas. (Sin embargo, es O (1) en la memoria)
Jon Skeet
1

Si ambas listas son demasiado grandes y cuando usamos la expresión lamda, llevará mucho tiempo recuperarlas. Es mejor usar linq en este caso para obtener la lista de parámetros:

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