LINQ lambda expressions in universal generic equality comparer
Implementation
Below you can find implementation we use as universal equality comparer. Only lambda expressions as in LINQ queries are needed to measure items. Class LambdaComparer is generic, so you can use it on any type you want to.
publicclass City
{publicstring Name { get; set;}publicint Population { get; set;}publicoverridestring ToString(){returnstring.Format("\tName: {0}\t, Population: {1}", Name, Population);}}
PublicClass City
PublicProperty Name()AsStringGetReturn m_Name
EndGetSet
m_Name = Value
EndSetEndPropertyPrivate m_Name AsStringPublicProperty Population()AsIntegerGetReturn m_Population
EndGetSet
m_Population = Value
EndSetEndPropertyPrivate m_Population AsIntegerPublicOverridesFunction ToString()AsStringReturnString.Format(vbTab &"Name: {0}"& vbTab &", Population: {1}", Name, Population)EndFunctionEndClass
Application showing typical use
class Program
{privatestaticvoid Main(){
var cities = CreateCities();
Console.WriteLine("Normal listing:");foreach(var city in cities)
Console.WriteLine(city);
Console.WriteLine("Press any key to continue...\n");
Console.ReadKey(true);
Console.WriteLine("Distinct by name:");foreach(var city in cities.Distinct(new LambdaComparer<City>((c1, c2)=> c1.Name.Equals(c2.Name),
c =>1/* force compare other than by instance */)))
Console.WriteLine(city);
Console.WriteLine("Press any key to continue...\n");
Console.ReadKey(true);
Console.WriteLine("More than one property is doubled:");foreach(var city in cities.Distinct(new LambdaComparer<City>((c1, c2)=> c1.Population.Equals(c2.Population)|| c2.Name.Equals(c2.Name),
c =>1/* force compare other than by instance */)))
Console.WriteLine(city);
Console.WriteLine("Press any key to continue...\n");
Console.ReadKey(true);
Console.WriteLine("Contains city with population of 789? :");
Console.WriteLine(cities.Contains(new City { Name ="City789", Population =789},
new LambdaComparer<City>((c1, c2)=> c1.Population.Equals(c2.Population),
c => c.GetHashCode()/* instance has nothing to do here */)));
Console.WriteLine("Press any key to continue...\n");
Console.ReadKey(true);
Console.WriteLine("HashSet with equality set to City.Name property? :");
var hashSet =new HashSet<City>(new LambdaComparer<City>((c1, c2)=> c1.Name.Equals(c2.Name),
c =>1/* force compare other than by instance */)){new City {Name ="aaa"},
new City {Name ="aba"},
new City {Name ="aaa"},
new City {Name ="baa"},
new City {Name ="aba"}};foreach(var city in hashSet)
Console.WriteLine(city);
Console.WriteLine("Press any key to exit...\n");
Console.ReadKey(true);}privatestatic IEnumerable<City> CreateCities(){returnnew List<City>{new City { Name ="City1", Population =123},
new City { Name ="City2", Population =456},
new City { Name ="City1", Population =789},
new City { Name ="City3", Population =123},
new City { Name ="City4", Population =987},
new City { Name ="City4", Population =654}};}}
Class Program
PrivateSharedSub Main()Dim cities = CreateCities()
Console.WriteLine("Normal listing:")ForEach city As var In cities
Console.WriteLine(city)Next
Console.WriteLine("Press any key to continue..."& vbLf)
Console.ReadKey(True)
Console.WriteLine("Distinct by name:")' force compare other than by instance ForEach city As var In cities.Distinct(New LambdaComparer(Of City)(Function(c1, c2) c1.Name.Equals(c2.Name), Function(c)1))
Console.WriteLine(city)Next
Console.WriteLine("Press any key to continue..."& vbLf)
Console.ReadKey(True)
Console.WriteLine("More than one property is doubled:")' force compare other than by instance ForEach city As var In cities.Distinct(New LambdaComparer(Of City)(Function(c1, c2) c1.Population.Equals(c2.Population) OrElse c2.Name.Equals(c2.Name), Function(c)1))
Console.WriteLine(city)Next
Console.WriteLine("Press any key to continue..."& vbLf)
Console.ReadKey(True)
Console.WriteLine("Contains city with population of 789? :")' instance has nothing to do here
Console.WriteLine(cities.Contains(New City()With{ _
Key .Name="City789", _
Key .Population=789 _
}, New LambdaComparer(Of City)(Function(c1, c2) c1.Population.Equals(c2.Population), Function(c) c.GetHashCode())))
Console.WriteLine("Press any key to continue..."& vbLf)
Console.ReadKey(True)
Console.WriteLine("HashSet with equality set to City.Name property? :")' force compare other than by instance Dim hashSet =New HashSet(Of City)(New LambdaComparer(Of City)(Function(c1, c2) c1.Name.Equals(c2.Name), Function(c)1)) From { _
New City()With{ _
Key .Name="aaa" _
}, _
New City()With{ _
Key .Name="aba" _
}, _
New City()With{ _
Key .Name="aaa" _
}, _
New City()With{ _
Key .Name="baa" _
}, _
New City()With{ _
Key .Name="aba" _
} _
}ForEach city As var In hashSet
Console.WriteLine(city)Next
Console.WriteLine("Press any key to exit..."& vbLf)
Console.ReadKey(True)EndSubPrivateSharedFunction CreateCities()As IEnumerable(Of City)ReturnNew List(Of City)() From { _
New City()With{ _
Key .Name="City1", _
Key .Population=123 _
}, _
New City()With{ _
Key .Name="City2", _
Key .Population=456 _
}, _
New City()With{ _
Key .Name="City1", _
Key .Population=789 _
}, _
New City()With{ _
Key .Name="City3", _
Key .Population=123 _
}, _
New City()With{ _
Key .Name="City4", _
Key .Population=987 _
}, _
New City()With{ _
Key .Name="City4", _
Key .Population=654 _
} _
}EndFunctionEndClass
Output
Normal listing:
Name: City1 , Population: 123
Name: City2 , Population: 456
Name: City1 , Population: 789
Name: City3 , Population: 123
Name: City4 , Population: 987
Name: City4 , Population: 654
Press any key to continue...
Distinct by name:
Name: City1 , Population: 123
Name: City2 , Population: 456
Name: City3 , Population: 123
Name: City4 , Population: 987
Press any key to continue...
More than one property is duplicated:
Name: City1 , Population: 123
Press any key to continue...
Contains city with population of 789? :
True
Press any key to continue...
HashSet with equality set to City.Name property :
Name: aaa , Population: 0
Name: aba , Population: 0
Name: baa , Population: 0
Press any key to exit...