views:

113

answers:

3

Hello Fellow Developers:

I have an issue that I am sure someone out here have solved easier than what I am thinking to do. I have a list that have name and number. Name is required and could be duplicate and number could only be one, but not required.

|name|number|
|A   |2     |
|A   |      |
|B   |      |
|C   |      |
|C   |      |
|D   |4     |
-------------

At this moment I am performing a list.Distinct() on the name part, but it does not care about the number section.

newlist = oldlist.Distinct().ToList();

If one name that is duplicate has a number I want to keep the one with the number, which is not happening. The case of two same names and two different numbers will not happen. Any ideas?

One more thing: At this moment I don't care about sorting since distinct take care of that.

I am adding all the code for better visibility of the StackOverflow Team:

    class _ClientComparer : IEqualityComparer<_Client>
{
    #region IEqualityComparer<_Client> Members

    public bool Equals(_Client x, _Client y)
    {
        if ((x.ClientNumber != 0) && (y.ClientNumber != 0))//Both clients with numbers
            if (x.ClientNumber == y.ClientNumber)//both clients number the same then same clients.
                return true;
            else //if not the same they are different
                return false;
        else if (x.ClientName == y.ClientName)
            return true;
        else
            return false;
    }

    public int GetHashCode(_Client obj)
    {
        if (obj.ClientNumber != 0)
            return obj.ClientNumber.GetHashCode();
        else
            return obj.ClientName.GetHashCode();
    }

Above the IEqualityComparer implementation and below the Distinct Call.

        public List<_Client> CollectAllClients()
    {
        List<_Client> ClientList = new List<_Client>();
        while (this.Read())
        {
            if (GetClientNumber() != 0)
                ClientList.Add(CreateClientInstance());
            else
                ClientList.AddRange(CreateClientsInstance());
        }
        ClientList = ClientList.Distinct<_Client>(new _ClientComparer()).ToList<_Client>() ;
        return ClientList;
    }
A: 

try implementing an IEqualityComparer for your type, and passing it as a parameter to Distinct (I'm assuming that your list hold a Tuple of string and a Nullable int (Tuple is not a .NET class - till .Net 4.0)

        private class c : IEqualityComparer<Tuple<string,int?>>
        {

            #region IEqualityComparer<Tuple<string,int?>> Members

            public bool Equals(Tuple<string, int?> x, Tuple<string, int?> y)
            {
                if (x.a.Equals(x.a) && x.b.Equals(y.b))
                    return true;
                return false;
            }

            public int GetHashCode(Tuple<string, int?> obj)
            {
                throw new NotImplementedException();
            }

            #endregion
        }

and then

List<Tuple<string,int?>> list;
.....
list.Distinct(new c());
RA
I think that will keep both "A" and "A2", which is not what OP wanted.
Groo
x.a.Equals(x.a) I sure hope that's always either true or throws a nullreferenceexception :)
Rune FS
It wasn't really a production ready code - just a direction to think about :)
RA
A: 

If the list is composed of objects that look like this:

class Record : IEquatable<Record>
{
    public string Name { get; set; }
    public int Number { get; set; }

    public bool Equals(Record r)
    {
        if (r == null) return false;
        return this.Name.Equals(r.Name) && this.Number.Equals(r.Number);
    }
}

where Number 0 indicated no number. You achieve the result by first sorting, then doing distinct. Distinct will keep a hashtable of each encountered element and check for existance on subsequent elements. So:

var newList = oldList.OrderByDescending(x => x.Number).Distinct();
eulerfx
+1  A: 

You can use grouping:

        List<MyObject> tests = new List<MyObject>() 
        { 
            new MyObject {Name = "A", Number = 2 },
            new MyObject {Name = "A", Number = null },
            new MyObject {Name = "B", Number = null},
            new MyObject {Name = "C", Number = null},
            new MyObject {Name = "C", Number = null},
            new MyObject {Name = "D", Number = 4}
        };

        var qry = from t in tests
                  group t by t.Name into g
                  select g.Max();

        qry.ToList();

With MyObject being:

public class MyObject : IComparable<MyObject>
{
    public string Name { get; set; }
    public int? Number { get; set; }

    public int CompareTo(MyObject other)
    {
        return Comparer<int?>.Default.Compare(this.Number, other.Number);
    }
}

If you have a repeated element with different numbers (like {A, 1}, {A, 2}) , the Max is chosen.

bruno conde