C Sharper
C Sharper

Reputation: 8626

Check if elements from one list elements present in another list

I have 2 c# classes -

class ABC
{
  string LogId;
  string Name;
}

class XYZ
{
  string LogId;
  string Name;
}

class Checker
{
  public void comparelists()
  {
    List<ABC> lstABC =new List<ABC>();
    lstABC.Add(new ABC...);
    lstABC.Add(new ABC...);
    lstABC.Add(new ABC...);

    List<XYZ> lstXYZ =new List<XYZ>();
    lstXYZ.Add(new XYZ...);
    lstXYZ.Add(new XYZ...);
    lstXYZ.Add(new XYZ...);

    var commonLogId = lstABC
      .Where(x => lstXYZ.All(y => y.LogId.Contains(x.LogId)))
      .ToList();


  }
}

As seen from the code , I want to fetch all logids from lstABC which are present in lstXYZ.

Eg. lstABC has ->

LogId="1", Name="somename1"
LogId="2", Name="somename2"
LogId="3", Name="somename3"
LogId="4", Name="somename4"
LogId="5", Name="somename5"

lstXYZ has ->

LogId="1", Name="somename11"
LogId="2", Name="somename22"
LogId="3", Name="somename33"
LogId="8", Name="somename8"
LogId="9", Name="somename9"

Then all logids from lstABC which are present in lstXYZ are - 1,2,3 ; so all those records are expected to get fetched.

But with below linq query -

var commonLogId = lstABC
  .Where(x => lstXYZ.All(y => y.LogId.Contains(x.LogId)))
  .ToList();

0 records are getting fetched/selected.

Upvotes: 2

Views: 401

Answers (3)

Jamiec
Jamiec

Reputation: 136074

It seems pretty unnatural to intersect entirely different types, so I would be tempted to interface the commonality and write an EqualityComparer:

class ABC : ILogIdProvider
{
    public string LogId {get;set;}
    public string Name;
}

class XYZ : ILogIdProvider
{
    public string LogId{get;set;}
    public string Name;
}

interface ILogIdProvider
{
    string LogId{get;}
}

class LogIdComparer : EqualityComparer<ILogIdProvider>
{
    public override int GetHashCode(ILogIdProvider obj) => obj.LogId.GetHashCode();
    
    public override bool Equals(ILogIdProvider x, ILogIdProvider y) => x.LogId == y.LogId;
}

Then you can Intersect the lists more naturally:

var res = lstABC.Intersect(lstXYZ, new LogIdComparer());

Live example: https://dotnetfiddle.net/0Tt6eu

Upvotes: 1

Good Night Nerd Pride
Good Night Nerd Pride

Reputation: 8442

You are using the wrong LINQ function. Try Any():

var commonLogId = lstABC
  .Where(x => lstXYZ.Any(y => y.LogId == x.LogId))
  .ToList();

Also note that the id comparison with Contains() was wrong. Just use == instead.

All() checks if all elements in a list satisfy the specified condition. Any() on the other hand only checks if at least one of the elements does.

Be aware that your implementation will be very slow when both lists are large, because it's runtime complexity grows quadratically with number of elements to compare. A faster implementation would use Join() which was created and optimized exactly for this purpose:

var commonLogIds = lstABC
  .Join(
     lstXYZ,
     x => x.LogId,  // Defines what to use as key in `lstABC`.
     y => y.LogId,  // Defines what to use as key in `lstXYZ`.
     (x, y) => x)   // Defines the output of matched pairs. Here
                    // we simply use the values of `lstABC`.
  .ToList();

Upvotes: 2

fubo
fubo

Reputation: 45947

approach with Any()

var res = lstABC.Where(x => (lstXYZ.Any(y => y.LogId == x.LogId))).Select(x => x.LogId);

https://dotnetfiddle.net/jRnUwS


another approach would be Intersect() which felt a bit more natural to me

var res = lstABC.Select(x => x.LogId).Intersect(lstXYZ.Select(y => y.LogId));

https://dotnetfiddle.net/7iWYDO

Upvotes: 2

Related Questions