Home > front end >  intersect two lists of objects on multiple values
intersect two lists of objects on multiple values

Time:03-11

Lets say I have two lists of the same class.

public class emailfilter
{
 public string from {get;set;}
 public string to {get;set;}
 public string cc {get;set;}
 public string subj {get;set;}
 public string body {get;set;}
 public string emailid {get;set;}
}
//there are two lists of type emailfilter. 1 list is formed dynamically from the config file
List<emailfilter> configfilterlist = //mock sudo code//
{
efilter tempobj = new efilter();
tempobj.from = config.from or "" if no value
tempobj.to = config.to or "" if no value
tempobj.cc = config.cc or "" if no value
tempobj.subj = config.subj or "" if no value
tempobj.body = config.body or "" if no value
configfilterlist.add(tempobj);
}
//List1 will never have an emailID
//List2 is formed from email items pulled from exchange and made into efilter objects and those do have an emailid.
//List2 will typically have all object fields populated. List1, the object fields are optional

So I want to compare/intersect list1 of filter items against list2 of email items to a combined list without duplicates that includes only the items that have all filter criteria of list1 and includes the mailid of list2. If there's no value for a value on List1, I want to ignore that and just match on the config values provided skipping over any "" blank strings. I'm hoping there's a way to do this with lambda and linq, but I haven't seen any examples with comparison on multiple values and ignoring others like in this case emailID.

UPDATE: Thank you @wertzui for providing the answer I needed to solve this. The final solution was just slightly different so updating the post/question with essentially the final solution in case it helps another lost soul.

public class emailfilter: IEquatable<emailfilter>
{
    public string from { get; set; }
    public string to { get; set; }
    public string cc { get; set; }
    public string subj { get; set; }
    public string body { get; set; }
    public string emailid { get; set; }
    
    public override int GetHashCode()
    {
        return System.HashCode.Combine(from, to, cc, subj, body);
    }
    
    public override bool Equals(object? obj) => Equals(obj as emailfilter);

    public bool Equals(emailfilter? other)
    {
        return
            other != null &&
            (from.Contains(other.from) || other.from == "") &&
            (to.Contains(other.sentto) || other.to == "") &&
            (cc.Contains(other.cc) || other.cc == "") &&
            (subj.Contains(other.subj) || other.subj == "") &&
            (body.Contains(other.body) || other.body == "");
    }
}

//emailsasfilters is List2 = all exchange emails as filter objects
var combinedSet = new HashSet<emailfilter>();
foreach (var filter in configfilterlist)  //configfilterlist is List1 = filters from Config
{
                    if (emailsasfilters.Contains(filter))
                    combinedSet.Add(emailsasfilters.ElementAt(emailsasfilters.IndexOf(filter)));
}
combinedSet.Dump();

CodePudding user response:

Since .Net 6, there is a new UnionBy method which you can use.

var combined = configfilterlist
    .UnionBy(
        exchangefilterlist, 
        e => new { e.from, e.to, e.cc, e.subj, e.body })
    .ToList();

Another method which works with older Framework versions is, to use a HashSet<T> and implement GetHashCode and Equals

public class emailfilter: IEquatable<emailfilter>
{
    public string from { get; set; }
    public string to { get; set; }
    public string cc { get; set; }
    public string subj { get; set; }
    public string body { get; set; }
    public string emailid { get; set; }
    
    public override int GetHashCode()
    {
        return System.HashCode.Combine(from, to, cc, subj, body);
    }
    
    public override bool Equals(object? obj) => Equals(obj as emailfilter);

    public bool Equals(emailfilter? other)
    {
        return
            other != null &&
            from == other.from &&
            to == other.to &&
            cc == other.cc &&
            subj == other.subj &&
            body == other.body;
    }
}
var combinedSet = new HashSet<emailfilter>(configfilterlist);
foreach (var email in exchangefilterlist)
{
    combinedSet.Add(email);
}
combinedSet.Dump();

  • Related