Skip to content

ritterim/filter

Repository files navigation

Filter RimDev.Filter NuGet badge RimDev.Filter NuGet downloads

"the classy way to filter collections"

This library allows an IEnumerable to be filtered using either a typed or anonymous class.

Installation

Install the RimDev.Filter NuGet package.

Install-Package RimDev.Filter

Usage

using RimDev.Filter.Generic;
using RimDev.Filter.Range;

public class Person
{
    public Person(string firstName, int favoriteNumber)
    {
        FavoriteNumber = favoriteNumber;
        FirstName = firstName;
    }

    public int FavoriteNumber { get; set; }
    public string FirstName { get; set; }
}

var people = new List<Person>()
{
    new Person("John", 1),
    new Person("Tom", 2),
    new Person("Jane", 3),
    new Person("Sally", 4)
};

IEnumerable<Person> filteredPeople = null;

// returns just the first-record.
filteredPeople = people.Filter(new
{
    FirstName = "John"
});

// returns the first and second-record.
filteredPeople = people.Filter(new
{
    FirstName = new[] { "John", "Tom" }
});

// returns the second-record.
filteredPeople = people.Filter(new
{
    FavoriteNumber = Range.FromString<int>("(1,3)")
});

// returns the first three-records.
filteredPeople = people.Filter(new
{
    FavoriteNumber = Range.FromString<int>("[1,4)")
});

Range-type

This is a new type which allows an easy way to represent a range of values when filtering. An instance can either be created manually or via a helper which takes a string formatted using standard interval notation.

While any type is allowed as a range, only certain types will work when filtering:

  • byte
  • char
  • DateTime
  • DateTimeOffset
  • decimal
  • double
  • float
  • int
  • long
  • sbyte
  • short
  • uint
  • ulong
  • ushort

Any other types will just silently get passed-over.

Usage

using RimDev.Filter.Range;
using RimDev.Filter.Range.Generic;

var range = new Range<int>()
{
    MinValue = 0,
    MaxValue = 10,
    IsMinInclusive = false,
    IsMaxInclusive = true
};

// or with helper.
var range = Range.FromString<int>("(0,10]");

Implicit casting

Instead of having to call the static-helper Range.FromString<T>, you can also leverage implicit casting support:

Range<int> range = "[1,5]";

// or...

// Type is Range<int>.
var range2 = (Range<int>)"[1,5]";

Open-ended support

Instead of having to specify both lower and upper-bound, you can truncate one of the two:

// x <= 5
var range = (Range<int>)"(,5]";

// range.MinValue.HasValue == false;

// or use Unicode

var range2 = (Range<int>)"(-∞,5]";
var range3 = (Range<int>)"[1,+∞)";

Short-syntax version

Some assumptions are made if enclosing-characters (i.e. [, (, ], )) are not used:

var range = (Range<int>)"123";

// range.MinValue == 123;
// range.MaxValue == 123;
// range.IsMinInclusive == true;
// range.IsMaxInclusive == true;

var range2 = (Range<int>)",456";

// range2.MinValue == null;
// range2.MaxValue == 456;
// range2.IsMinInclusive == true;
// range2.IsMaxInclusive == true;

var range3 = (Range<int>)"(123,";

// range3.MinValue == 123;
// range3.MaxValue == 123;
// range3.IsMinInclusive == false;
// range3.IsMaxInclusive == true;

Current limitations

  • The library currently only works with class-type collections.
  • Constant filter-value (i.e. non-enumerable or range) exceptions are trapped within the Filter call.

License

MIT

Contributing

Issue documentation and pull-requests are welcomed. This project follows the fork & pull model.