151

I have a list of parameters like this:

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

IEnumerable<Parameter> parameters;

And a array of strings i want to check it against.

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

I want to iterate over the parameter list and check if the source property is equal to any of the myStrings array. I can do this with nested foreach's but i would like to learn how to do it in a nicer way as i have been playing around with linq and like the extension methods on enumerable like where etc so nested foreachs just feel wrong. Is there a more elegant preferred linq/lambda/delegete way to do this.

Thanks

Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73
gdp
  • 8,032
  • 10
  • 42
  • 63

4 Answers4

327

You could use a nested Any() for this check which is available on any Enumerable:

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

Faster performing on larger collections would be to project parameters to source and then use Intersect which internally uses a HashSet<T> so instead of O(n^2) for the first approach (the equivalent of two nested loops) you can do the check in O(n) :

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

Also as a side comment you should capitalize your class names and property names to conform with the C# style guidelines.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • thanks seems to be what im looking for i will try it out. Need to play around with the functional side of things a bit more. regarding capitalising class and properties, i do i just was forgot when wrote the example above. – gdp Jun 19 '12 at 00:51
  • 1
    Why O(n^2)? Isn't it O(n*m) as we are talking abount two variables and not one? Since m (the parametes) are a constant, it's the same as O(n). I don't see how intersect should be much faster here? But agreed, Intersect has the potential to be faster, but is not guaranteed. – Squazz Oct 20 '16 at 10:59
  • You are right that it should be O(n*m) - m is not a constant though - it is the size of one of the lists, even though in the particular example given it might be "2". Even constant values though are not negligible in practice - for all non-trivial list lengths the `Intersect` will be faster - if the lists are trivially short, it does not matter one way or another (in that case performance probably is not your concern at all anyway) – BrokenGlass Oct 20 '16 at 15:46
  • how can u figure out the list index where the condition becomes true ? I have a list with sentences. I have an array with particular words. I want indexes of the list if the sentence have atleast one words from the array. @BrokenGlass – kirushan Mar 17 '17 at 02:44
  • 2
    Performance-wise, wouldn't `parameters.Any(x => myStrings.Contains(x.source));` be better than your first example? – Fluppe May 03 '18 at 15:27
  • it's the same @Fluppe - `Array.Contains` is also O(n) – BrokenGlass Jul 29 '18 at 21:38
  • 1
    Notice: starting with .NET 6 there is an extension method `IntersectBy()` which eliminates the necessacity to first project the source - https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.intersectby – Rand Random Dec 21 '22 at 09:45
11

Here is a sample to find if there are match elements in another list

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
  • 3,754
  • 4
  • 33
  • 41
  • 3
    Note that if the lists involved are large, this will end up being a lot slower than the `Intersect` approach, as it's O(N*M) in the sizes of the lists. (It's O(1) in memory though.) – Jon Skeet Feb 24 '19 at 09:43
6

If both the list are too big and when we use lamda expression then it will take a long time to fetch . Better to use linq in this case to fetch parameters list:

var items = (from x in parameters
                join y in myStrings on x.Source equals y
                select x)
            .ToList();
Maximilian Ast
  • 3,369
  • 12
  • 36
  • 47
Umang Agarwal
  • 61
  • 1
  • 2
6
list1.Select(l1 => l1.Id).Intersect(list2.Select(l2 => l2.Id)).ToList();
var list1 = await _service1.GetAll();
var list2 = await _service2.GetAll();

// Create a list of Ids from list1
var list1_Ids = list1.Select(l => l.Id).ToList();

// filter list2 according to list1 Ids
var list2 = list2.Where(l => list1_Ids.Contains(l.Id)).ToList();
M Komaei
  • 7,006
  • 2
  • 28
  • 34
  • 1
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) will help people understand the reasons for your code suggestion. – Gerhard Feb 14 '22 at 08:32
  • 1
    You should probably add a line that checks the length of list 2 for completeness' sake. It would probably also be faster to use `Intersect`, wouldn't it? – General Grievance Feb 18 '22 at 13:41