Supreeth Supreeth - 3 years ago 83
C# Question

How to Merge two lists and Merge it's inner lists without duplication in C#

I'm trying to merge two generic list using LINQ-

List<LinkedTable> FirstLink
List<LinkedTable> SecondLink


As shown in the Class below, my generic list itself has a generic list in it.

public class LinkedTable
{
public string TableId { get; set; }
public string TableName { get; set; }
public List<Link> innerLinks { get; set; }
}

public class Link
{
public Boolean linkFlag;
public string Descriptor { get; set; }
public string RecordId { get; set; }
}


When I merge the two lists, the new list doesn't contain both the "innerLinks" records of FirstLink and SecondLink.
I have tried the following code:

FirstLink = FirstLink.Concat(SecondLink)
.GroupBy(e1 => e1.TableId)
.Select(e2 => e2.FirstOrDefault())
.ToList();


Now FirstLink will get all the Tables grouped by "TableId ", but a few "innerLinks" from SecondLink is missing.

I need both the list of "innerLinks" from FirstLink and SecondLink in the new merged List without repetition.

Example:

FirstLink[0].innerLinks[0]
.innerLinks[1]
.innerLinks[2]

SecondLink[0].innerLinks[1]
.innerLinks[2]
.innerLinks[3]


Merged Link should be:

FirstLink[0].innerLinks[0]
.innerLinks[1]
.innerLinks[2]
.innerLinks[3]

Answer Source

Here's an option:

First, you'll have to provide a way to tell Linq what makes a Link equal to another. You can do this by any of this methods:

  • creating a class the implements IEqualityComparer<Link> and pass an instance of it as parameter to Distinct;
  • implementing IEquatable<Link> and overriding GetHashCode on the Link class
  • overriding Equals and GetHashCode on the Link class.

Assuming that RecordId is the unique identifier for a Link object, this is how you do it by implementing IEquatable<Link>:

public class Link : IEquatable<Link>
{
    public Boolean linkFlag;
    public string Descriptor { get; set; }
    public string RecordId { get; set; }

    public bool Equals(Link other)
    {
        //Adjust for a suiting identifier and do all the sanity checks, if needed.
        return this.RecordId == other.RecordId;
    }

    public override int GetHashCode()
    {
        //You can also use another GetHash approach that suits you better.
        return this.RecordId.GetHashCode();
    }
}

Then, you can Concat both lists, then group by TableId and TableName. Last, you use SelectMany on the grouped LinkedTable's innerLinks to select all Links contained on that group. The Distinct will have to take an instance of the IEqualityComparer in case you opted to go that way.

var merged = 
    from item in FirstLink.Concat(SecondLink)
    group item by new { Id = item.TableId, Name = item.TableName } into tbGp
    select new LinkedTable
    {
        TableId = tbGp.Key.Id,
        TableName = tbGp.Key.Name,
        innerLinks = tbGp.SelectMany(p => p.innerLinks).Distinct().ToList()
    };

Distinct and IEquatable<T> explained on MSDN
Overriding Equals and GetHashCode on MSDN

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download