简体   繁体   中英

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.

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

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();

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM