Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stephencleary/comparers
The last comparison library you'll ever need!
https://github.com/stephencleary/comparers
c-sharp comparer comparers comparison comparison-library dotnet equality equality-comparers icomparable icomparer iequalitycomparer sort
Last synced: 4 days ago
JSON representation
The last comparison library you'll ever need!
- Host: GitHub
- URL: https://github.com/stephencleary/comparers
- Owner: StephenCleary
- License: mit
- Created: 2014-04-21T21:29:22.000Z (over 10 years ago)
- Default Branch: main
- Last Pushed: 2023-12-09T16:14:07.000Z (about 1 year ago)
- Last Synced: 2024-12-14T04:03:44.352Z (11 days ago)
- Topics: c-sharp, comparer, comparers, comparison, comparison-library, dotnet, equality, equality-comparers, icomparable, icomparer, iequalitycomparer, sort
- Language: C#
- Homepage:
- Size: 533 KB
- Stars: 427
- Watchers: 29
- Forks: 33
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
![Logo](src/icon.png)
# Comparers [![Build status](https://github.com/StephenCleary/Comparers/workflows/Build/badge.svg)](https://github.com/StephenCleary/Comparers/actions?query=workflow%3ABuild) [![codecov](https://codecov.io/gh/StephenCleary/Comparers/branch/main/graph/badge.svg)](https://codecov.io/gh/StephenCleary/Comparers) [![NuGet version](https://badge.fury.io/nu/Nito.Comparers.svg)](https://www.nuget.org/packages/Nito.Comparers) [![API docs](https://img.shields.io/badge/API-FuGet-blue.svg)](https://www.fuget.org/packages/Nito.Comparers)
The last comparison library you'll ever need! Wide platform support; fluent syntax.
## Creating Comparers
Install the [`Nito.Comparers` NuGet package](https://www.nuget.org/packages/Nito.Comparers). By default, this includes the [extension package for LINQ](https://www.nuget.org/packages/Nito.Comparers.Linq) support.
The comparer types are in the namespace `Nito.Comparers`.
Let's say you've got a collection of your POCOs:
```c#
class Person
{
public string FirstName { get; }
public string LastName { get; }
}
List list = ...;
```Here's an easy way to sort them all by last name and then first name:
```c#
IComparer nameComparer =
ComparerBuilder.For()
.OrderBy(p => p.LastName)
.ThenBy(p => p.FirstName);
list.Sort(nameComparer);
```### Implementing Comparable Types
How about having Person implement it?
Let's face it: implementing comparison in .NET is a real pain. `IComparable`, `IComparable`, `IEquatable`, `Object.Equals`, *and* `Object.GetHashCode`?!?!
But it's easy with a base type:```c#
class Person : ComparableBase
{
static Person()
{
DefaultComparer =
ComparerBuilder.For()
.OrderBy(p => p.LastName)
.ThenBy(p => p.FirstName);
}public string FirstName { get; }
public string LastName { get; }
}
````ComparableBase` auto-magically implements all the comparable interfaces, including correct overrides of `Object.Equals` and `Object.GetHashCode`.
### Using Comparers in Hash Containers
What about hash-based containers? Every single comparer produced by the Comparers library also implements equality comparison!
```c#
IEqualityComparer nameComparer =
ComparerBuilder.For()
.OrderBy(p => p.LastName)
.ThenBy(p => p.FirstName);
Dictionary dict = new Dictionary(nameComparer);
```### Equality Comparers
Sometimes, you can only define equality. Well, good news: there are equality comparer types that parallel the full comparer types.
```c#
class Entity : EquatableBase
{
static Entity()
{
DefaultComparer =
EqualityComparerBuilder.For()
.EquateBy(e => e.Id);
}public int Id { get; }
}
```### Working with Sequences
Sequences are sorted lexicographically. The `Sequence` operator takes an existing comparer for one type, and defines a lexicographical comparer for sequences of that type:
```c#
var nameComparer =
ComparerBuilder.For()
.OrderBy(p => p.LastName)
.ThenBy(p => p.FirstName);
List> groups = ...;
groups.Sort(nameComparer.Sequence());
```There's also natural extensions for LINQ that allow you to define comparers on-the-fly (particularly useful for anonymous types):
```c#
IEnumerable people = ...;
var anonymousProjection = people.Select(x => new { GivenName = x.FirstName, Surname = x.LastName });
var reduced = anonymousProjection.Distinct(c => c.EquateBy(x => x.Surname));
```### Dynamic Sorting
Need to sort dynamically at runtime? No problem!
```c#
var sortByProperties = new[] { "LastName", "FirstName" };
IComparer comparer = ComparerBuilder.For().Null();
foreach (var propertyName in sortByProperties)
{
var localPropertyName = propertyName;
Func selector = p => p.GetType().GetProperty(localPropertyName).GetValue(p, null) as string;
comparer = comparer.ThenBy(selector);
}
```### Complex Sorting
Want a cute trick? Here's one: `true` is "greater than" `false`, so if you want to order by some weird condition, it's not too hard:
```c#
// Use the default sort order (last name, then first name), EXCEPT all "Smith"s move to the head of the line.
var comparer =
ComparerBuilder.For()
.OrderBy(p => p.LastName == "Smith", descending: true)
.ThenBy(ComparerBuilder.For().Default());
list.Sort(comparer);
```By default, `null` values are "less than" anything else, but you can use the same sort of trick to sort them as "greater than" non-`null` values (i.e., `null`s will be last in a sorted collection):
```c#
List myInts = ...;
var comparer =
ComparerBuilder.For()
.OrderBy(i => i == null, specialNullHandling: true)
.ThenBy(ComparerBuilder.For().Default());
myInts.Sort(comparer);
// Note: we need to pass "specialNullHandling"; otherwise, the default null-ordering rules will apply.
```### More?!
For full details, see [the detailed docs](doc).
### What's with the flying saucer?
Other languages provide a comparison operator `<=>`, which is called the "spaceship operator". This library provides similar capabilities for C#, hence the "spaceship logo".