Vahid
Vahid

Reputation: 5444

Remove duplicate inner lists from a list of list<object> in c#

I apologize for the ambiguous title. I couldn't keep it clear and concise at the same time. So feel free to change it.

I have a big List which contains several other Lists. And these inner Lists contain Column objects.

List<List<Column>> listOfAllColumns;

Let's say my inner lists contain different Column objects like this:

list1 = {c1, c1, c2}
list2 = {c1, c2, c1}
list3 = {c2, c3}
list4 = {c1,c1, c2}

And the big list contains these lists: listOfAllColumns = {list1, list2, list3, list4}

Now I want a method that removes duplicate lists from the listOfAllColumns list. For example, it will look into the list above and remove list4.

list1: c1,c1,c2
list2: c1,c2,c1
list3: c2,c3
list4: c1,c1,c2 (it is equal to list1 so it is a duplicate)

Here is my code:

public class ColumnList
{
    public void RemoveDuplicateColumnTypes()
    {

        Column c1 = new Column() { SectionName = "C50", StirrupType = "Tie" };
        Column c2 = new Column() { SectionName = "C50", StirrupType = "Spiral" };
        Column c3 = new Column() { SectionName = "C40", StirrupType = "Tie" };


        List<Column> list1 = new List<Column>() { c1, c1, c2 };
        List<Column> list2 = new List<Column>() { c1, c2, c1 };
        List<Column> list3 = new List<Column>() { c2, c3 };
        List<Column> list4 = new List<Column>() { c1, c1, c2 };


        List<List<Column>> listOfAllColumns = new List<List<Column>>() { list1, list2, list3, list4 };

        var result = listOfAllColumns.Distinct();

    }
}

class Column
{
    public string SectionName;
    public string StirrupType;
    public int StirrupSize;
    public double StirrupSpacing;
}

By the way the order is important, so for example {c1, c2, c1} is different than {c2,c1,c1}.

Upvotes: 2

Views: 925

Answers (2)

Servy
Servy

Reputation: 203844

What you need is an IEqualityComparer that is able to compare different sequences. This isn't terribly hard, given that it also has a way of comparing the items within it:

public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    private IEqualityComparer<T> comparer;
    public SequenceComparer(IEqualityComparer<T> comparer = null)
    {
        this.comparer = comparer ?? EqualityComparer<T>.Default;
    }
    public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
    {
        return x.SequenceEqual(y, comparer);
    }

    public int GetHashCode(IEnumerable<T> sequence)
    {
        unchecked
        {
            int hash = 19;
            foreach (var item in sequence)
                hash = hash * 79 + comparer.GetHashCode(item);
            return hash;
        }
    }
}

Now all you need to do is create an IEqualityComparer<Column> that is capable of comparing two column objects (through whatever meaningful way you want, presumably the default implementation is not sufficient).

Then you can just pass those to Distinct:

var query = listOfAllColumns.Distinct(
    new SequenceComparer<Column>(new ColumnComparer()));

Upvotes: 5

Tim Schmelter
Tim Schmelter

Reputation: 460238

I would implement a custom IEqualityComparer<IEnumerable<Column>> which you can use for Distinct:

public class ColumnListComparer : IEqualityComparer<IEnumerable<Column>>
{
    public bool Equals(IEnumerable<Column> x, IEnumerable<Column> y)
    {
        if (x == null || y == null) return false;
        if (object.ReferenceEquals(x, y)) return true;
        return x.SequenceEqual(y);
    }

    public int GetHashCode(IEnumerable<Column> obj)
    {
        unchecked
        {
            int hash = 17;
            foreach(Column col in obj)
            {
                hash = hash * 23 + (col == null ? 0 : col.GetHashCode());
            }
            return hash;
        }
    }
}

Now this works:

var result = listOfAllColumns.Distinct(new ColumnListComparer());

You also need to override Equals + GetHashCode in your class Column:

public class Column
{
    public string SectionName;
    public string StirrupType;
    public int StirrupSize;
    public double StirrupSpacing;

    public override bool Equals(object obj)
    {
        Column col2 = obj as Column;
        if(col2 == null) return false;
        return SectionName    == col2.SectionName
            && StirrupType    == col2.StirrupType 
            && StirrupSize    == col2.StirrupSize
            && StirrupSpacing == col2.StirrupSpacing;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + (SectionName ?? "").GetHashCode();
            hash = hash * 23 + (StirrupType ?? "").GetHashCode();
            hash = hash * 23 + StirrupSize.GetHashCode();
            hash = hash * 23 + StirrupSpacing.GetHashCode();
            return hash;
        }
    }
}

Upvotes: 2

Related Questions