namespace ConsoleApplication22
using System.Collections.Generic;
using System.Collections;
using static System.Console;
using static System.String;
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 Set<double> Range(double min, double max) =>
static void Report(string title, IEnumerable<object> args) =>
WriteLine($"{title}: {Join(",", args)}");
public static void Main()
var soundings = Sounding.Fakes();
Set<double> negative = Less(0);
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);
Report("Job well done", soundings & !failed);
Report("To do", soundings & failed);
Report("Big upcoming expenses", soundings & failed & deep);
public static Sounding[] Fakes() => new[]
new Point { Depth = -10, Pressure = 10, Channels = new[] { 1d, 2d, 3d } },
new Point { Depth = -15, Pressure = 1000, Channels = new[] { 1d, 2d, 3d } }
new Point { Depth = -10, Pressure = 10, Channels = new[] { 1d, 2d, 3d } },
new Point { Depth = -50, Pressure = 1000, Channels = new[] { 1d, 2d, 3d } }
Name ="Deep with bad data",
new Point { Depth = -25, Pressure = 10, Channels = new[] { 1d, 2d, 3d } },
new Point { Depth = -50, Pressure = 1000, Channels = new[] { -1d, -2d, 3d } }
public string Name { get; set; }
public Point[] Points { get; set; }
public override string ToString() => Name;
public double Depth { get; set; }
public double Pressure { get; set; }
public double[] Channels { get; set; }
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);
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)
Func<T, IEnumerable<TResult>> Selector { get; }
public Set(Predicate<T> predicate)
public static Enumerable<T> operator &(Set<T> left, T right) =>
left.Predicate(right) ? new Enumerable<T>(right) : Enumerable<T>.Empty;
public static Enumerable<T> operator &(T left, Set<T> right) =>
right.Predicate(left) ? new Enumerable<T>(left) : Enumerable<T>.Empty;
public static Set<T> operator &(Set<T> left, Set<T> right) =>
new Set<T>(i => left.Predicate(i) && right.Predicate(i));
public static Enumerable<T> operator &(Set<T> left, IEnumerable<T> right) =>
new Enumerable<T>(right.Where(i => left.Predicate(i)));
public static Enumerable<T> operator &(IEnumerable<T> left, Set<T> right) =>
new Enumerable<T>(left.Where(i => right.Predicate(i)));
public static Set<T> operator |(Set<T> left, T right) =>
new Set<T>(i => left.Predicate(i) || right.Equals(i));
public static Set<T> operator |(T left, Set<T> right) =>
new Set<T>(i => left.Equals(i) || right.Predicate(i));
public static Set<T> operator |(Set<T> left, Set<T> right) =>
new Set<T>(i => left.Predicate(i) || right.Predicate(i));
public static Set<T> operator |(Set<T> left, IEnumerable<T> right) =>
new Set<T>(i => left.Predicate(i) || right.Contains(i));
public static Set<T> operator |(IEnumerable<T> left, Set<T> right) =>
new Set<T>(i => left.Contains(i) || right.Predicate(i));
public static Set<T> operator -(Set<T> left, T right) =>
new Set<T>(i => left.Predicate(i) && !right.Equals(i));
public static Set<T> operator -(T left, Set<T> right) =>
new Set<T>(i => left.Equals(i) && !right.Predicate(i));
public static Set<T> operator -(Set<T> left, Set<T> right) =>
new Set<T>(i => left.Predicate(i) && !right.Predicate(i));
public static Set<T> operator -(Set<T> left, IEnumerable<T> right) =>
new Set<T>(i => left.Predicate(i) && !right.Contains(i));
public static Enumerable<T> operator -(IEnumerable<T> left, Set<T> right) =>
new Enumerable<T>(left.Where(i => !right.Predicate(i)));
public static Set<T> operator !(Set<T> set) =>
new Set<T>(i => !set.Predicate(i));
Predicate <T> Predicate { get; }
class Enumerable<T> : IEnumerable<T>
public static readonly Enumerable<T> Empty = new Enumerable<T>();
public static implicit operator bool(Enumerable<T> intersection) => intersection.Any();
public Enumerable(params T[] items)
public Enumerable(IEnumerable<T> items)
public IEnumerator<T> GetEnumerator() => Items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerable<T> Items { get; }