Supreeth
Supreeth

Reputation: 21

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]

Upvotes: 1

Views: 1271

Answers (2)

Gabriel Rainha
Gabriel Rainha

Reputation: 1743

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

Upvotes: 1

user449689
user449689

Reputation: 3154

Your query doesn't work because when you are grouping you are taking the first element of the Group and its list of Link objects.

To achieve your result you should try the following code:

var FirstLink = FirstLink
    .Concat(SecondLink)
    .GroupBy(e1 => e1.TableId)
    // Don't take the first item, but create a new one with the items you need
    .Select(e2 => new LinkedTable
        {
            TableId = e2.Key,
            TableName = e2.First().TableName,
            innerLinks = e2.SelectMany(x => x.innerLinks).ToList()
        })
    .ToList();

Upvotes: 1

Related Questions