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 '16 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\$ – Dmitry Nogin Jun 16 '16 at 6:41
  • \$\begingroup\$ @t3chb0t I did my best this time :) \$\endgroup\$ – Dmitry Nogin Jun 16 '16 at 14:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.