Up-to-date version: IEnumerable and Predicate Sets in .NET (Complete, Explained).

Previously: Countable and uncountable sets in .NET (clean version).

Disclaimer: Please do not interpret my attempts to gain maximum from .NET as some kind of socially unacceptable behavior. You, probably, know someone who does it to his/her car. It is a very good way to learn and explore a hospital nearby :)

Update: Set operations *, - have been changed to &,| as they are more common for expressing set operations.

Reason to have sets: Just because it streamlines IEnumerable<T> filtering. I will probably define some kind of lambda language for set composition, but look how easy and natural it is to play with them in integration scenarios (online demo):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using static System.Console;
using static System.String;
using static Selection;

class Program
    static Set<double> Less(double max) =>
        new Set<double>(v => v < max);

    static Set<double> Bigger(double min) =>
        new Set<double>(v => v > min);

    static void Main(string[] args)
        var soundings = Sounding.Fakes();

        // business layer – not happy; definitely need some lambda 
        // language for composition
        Set<double> negative = Less(0);

        // @ t3chb0t look at the end of the line – this one is for you! 
        // Also my first attempt to define pipe operator in C# :)
        Set<Point> shallow = negative & Bigger(-20) & Select((Point p) => p.Depth);
        Set<Point> squeezed = Bigger(100) & Select((Point p) => p.Pressure);
        Set<Point> outliers = negative & SelectMany((Point p) => p.Channels);

        Set<Sounding> deep = shallow & SelectMany((Sounding s) => s.Points);
        Set<Sounding> failed = (squeezed & shallow | outliers) & SelectMany((Sounding s) => s.Points);

        // reporting looks just good; and it is important as 
        // it is usually very volatile
        Report("Job well done", soundings & !failed);
        Report("To do", soundings & failed);
        Report("Big upcoming expenses", soundings & failed & deep);

    static void Report(string title, IEnumerable<object> args) =>
        WriteLine($"{title}: {Join(",", args)}");


Where new library code is:

static class Selection
    public static Selection<T, TResult> Select<T, TResult>(Func<T, TResult> selector) =>
        new Selection<T, TResult>(selector);

    public static Selection<T, TResult> SelectMany<T, TResult>(Func<T, IEnumerable<TResult>> selector) =>
        new Selection<T, TResult>(selector);

// represents some kind of data set, so intersection operator looks ok
class Selection<T, TResult>     {
    public static Set<T> operator &(Set<TResult> left, Selection<T, TResult> right) =>
        new Set<T>(r => left & right.Selector(r));

    public static Set<T> operator &(Selection<T, TResult> left, Set<TResult> right) =>
        new Set<T>(r => right & left.Selector(r));

    public Selection(Func<T, TResult> selector)
        Selector = (T i) => new[] { selector(i) };

    public Selection(Func<T, IEnumerable<TResult>> selector)
        Selector = selector;

    Func<T, IEnumerable<TResult>> Selector { get; }

P.S. It is not for production yet, just some kind of working 2 am experiment :)

  • 2
    \$\begingroup\$ Oh, an extra example for me - that's nice of you ;-) I find your experiments are interesing but at the same time they are pretty hard to comprehend. \$\endgroup\$
    – t3chb0t
    Jun 16, 2016 at 6:35
  • 1
    \$\begingroup\$ @t3chb0t Oh, it is just another example of "Arabic programming" as you named it :) I suddenly end up with a LINQ like select statement - at the end of the string instead of beginning :) \$\endgroup\$ Jun 16, 2016 at 6:41
  • \$\begingroup\$ @t3chb0t I did my best this time :) \$\endgroup\$ Jun 16, 2016 at 14:23


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.