How to use Distinct() in LINQ and how to pass own comparer
I am querying a table called STUDENT.I开发者_JAVA百科 want to retrieve 2 values, the STUDENT_ID, and the TIME (Both are strings). However, I only want the distinct values of STUDENT_ID. When I use Distinct() with only STUDENT_ID, I do get unique values. But the moment I include TIME, all the values show up because the times in the table are all different. I also tried to make my own Comparer class, and pass an instance to Distinct().
public class MyCompare : IEqualityComparer<IQueryable>
{
public bool Equals(DataRow x, DataRow y)
{
return (x.Field<string>("STUDENT_ID") == y.Field<string>("STUDENT_ID"));
}
public int GetHashCode(DataRow obj)
{
return obj.ToString().GetHashCode();
}
}
However, I get 4 errors.
1). Is there a way to use distinct on 2 values? ( Since it does sort if it's just STUDENT_ID) I want it to show the unique values for STUDENT_ID and show the corresponding TIMES.
OR.. 2. How do I make a working Comparer? I get the following errors.
a. Error 1 'System.Linq.IQueryable' does not contain a definition for 'Distinct' and the best extension method overload 'System.Linq.ParallelEnumerable.Distinct(System.Linq.ParallelQuery, System.Collections.Generic.IEqualityComparer)' has some invalid arguments C:\Users\KC\Desktop\SoulScanner\SoulScanner\SearchByTime.xaml.cs 360 23 SoulScanner
b. Error 4 Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable' to 'System.Linq.IQueryable' C:\Users\KC\Desktop\SoulScanner\SoulScanner\SearchByTime.xaml.cs 363 43 SoulScanner
c. Error 2 Instance argument: cannot convert from 'System.Linq.IQueryable' to 'System.Linq.ParallelQuery' C:\Users\KC\Desktop\SoulScanner\SoulScanner\SearchByTime.xaml.cs 360 23 SoulScanner
d. Error 3 The best overloaded method match for 'SoulScanner.dgvRecords.dgvRecords(System.Linq.IQueryable)' has some invalid arguments C:\Users\KC\Desktop\SoulScanner\SoulScanner\SearchByTime.xaml.cs 363 28 SoulScanner
Your comparer should really be implementing IEqualityComparer<DataRow>
- it's comparing rows, not the whole query.
Once that's fixed, however, your GetHashCode
method is still broken - it's returning the hash of the result of the ToString
call on the row itself, instead of just using the STUDENT_ID field. If ToString
came up with a reasonable string representation of all the fields in the row, it would be completely broken. If it's actually just returning the class name (which is the default behaviour of ToString
) then it's useless rather than broken :) You should use something like this:
public int GetHashCode(DataRow row)
{
string id = row.Field<string>("STUDENT_ID");
return id == null ? 0 : id.GetHashCode();
}
If you want to be distinct on two values, you need to use both of those in your hash and equality comparisons, that's all. Your equality comparison would have two equality checks and only return true if both passed. The hash code method would probably obtain two hashes (one for each field) and combine them together, e.g.
// Compute hashes for field1 and field2
...
int hash = 17;
hash = hash * 31 + hashForField1;
hash = hash * 31 + hashForField2;
return hash;
精彩评论