I have a table that has combo pairs identifiers, and I use that to go through CSV files looking for matches. I'm trapping the unidentified pairs in a List, and sending them to an output box for later addition. I would like the output to only have single occurrences of unique pairs. The class is declared as follows:

    public class Unmatched:IComparable<Unmatched>
{
    public string first_code { get; set; }
    public string second_code { get; set; }

    public int CompareTo(Unmatched other)
    {

        if (this.first_code == other.first_code)
        {
            return this.second_code.CompareTo(other.second_code);
        }

        return other.first_code.CompareTo(this.first_code);
    }
 }

One note on the above code: This returns it in reverse alphabetical order, to get it in alphabetical order use this line:

return this.first_code.CompareTo(other.first_code);

Here is the code that adds it. This is directly after the comparison against the datatable elements

unmatched.Add(new Unmatched() 
{ first_code = fields[clients[global_index].first_match_column]
, second_code = fields[clients[global_index].second_match_column] });

I would like to remove all pairs from the list where both first code and second code are equal, i.e.;

PTC,138A
PTC,138A
PTC,138A
MA9,5A
MA9,5A
MA9,5A
MA63,138A
MA63,138A
MA59,87BM
MA59,87BM

Should become:

PTC, 138A
MA9, 5A
MA63, 138A
MA59, 87BM

I have tried adding my own Equate and GetHashCode as outlined here: http://www.morgantechspace.com/2014/01/Use-of-Distinct-with-Custom-Class-objects-in-C-Sharp.html

The SE links I have tried are here:

How would I distinct my list of key/value pairs

Get list of distinct values in List<T> in c#

Get a list of distinct values in List

All of them return a list that still has all the pairs. Here is the current code (Yes, I know there are two distinct lines, neither appears to be working) that outputs the list:

    parser.Close();
    List<Unmatched> noDupes = unmatched.Distinct().ToList();
    noDupes.Sort();
    noDupes.Select(x => x.first_code).Distinct();

    foreach (var pair in noDupes)
    {
        txtUnmatchedList.AppendText(pair.first_code + "," + pair.second_code + Environment.NewLine);
    }

Here is the Equate/Hash code as requested:

public bool Equals(Unmatched notmatched)
{

    //Check whether the compared object is null.  
    if (Object.ReferenceEquals(notmatched, null)) return false;

    //Check whether the compared object references the same data.  
    if (Object.ReferenceEquals(this, notmatched)) return true;

    //Check whether the UserDetails' properties are equal.  
    return first_code.Equals(notmatched.first_code) && second_code.Equals(notmatched.second_code);
}

// If Equals() returns true for a pair of objects   
// then GetHashCode() must return the same value for these objects.  

public override int GetHashCode()
{

    //Get hash code for the UserName field if it is not null.  
    int hashfirst_code = first_code == null ? 0 : first_code.GetHashCode();

    //Get hash code for the City field.  
    int hashsecond_code = second_code.GetHashCode();

    //Calculate the hash code for the GPOPolicy.  
    return hashfirst_code ^ hashsecond_code;
}

I have also looked at a couple of answers that are using queries and Tuples, which I honestly don't understand. Can someone point me to a source or answer that will explain the how (And why) of getting distinct pairs out of a custom list?

(Side question-Can you declare a class as both IComparable and IEquatable?)

有帮助吗?

解决方案

The problem is you are not implementing IEquatable<Unmatched>.

public class Unmatched : IComparable<Unmatched>, IEquatable<Unmatched>

EqualityComparer<T>.Default uses the Equals(T) method only if you implement IEquatable<T>. You are not doing this, so it will instead use Object.Equals(object) which uses reference equality.

The overload of Distinct you are calling uses EqualityComparer<T>.Default to compare different elements of the sequence for equality. As the documentation states, the returned comparer uses your implementation of GetHashCode to find potentially-equal elements. It then uses the Equals(T) method to check for equality, or Object.Equals(Object) if you have not implemented IEquatable<T>.

You have an Equals(Unmatched) method, but it will not be used since you are not implementing IEquatable<Unmatched>. Instead, the default Object.Equals method is used which uses reference equality.

Note your current Equals method is not overriding Object.Equals since that takes an Object parameter, and you would need to specify the override modifier.

其他提示

For an example on using Distinct see here.

You have to implement the IEqualityComparer<TSource> and not IComparable<TSource>.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top