The OpenD Programming Language

Filter

Implements the higher order filter function. The predicate is passed to mir.functional.naryFun, and can either accept a string, or any callable that can be executed via pred(element).

@fmamath
struct Filter (
alias pred
Range
) {
Range _input;
version(assert)
bool _freshEmpty;
}

Parameters

pred

Function to apply to each element of range

Return Value

filter!(pred)(range) returns a new range containing only elements x in range for which pred(x) returns true.

Examples

int[] arr = [ 0, 1, 2, 3, 4, 5 ];

// Filter below 3
auto small = filter!(a => a < 3)(arr);
assert(equal(small, [ 0, 1, 2 ]));

// Filter again, but with Uniform Function Call Syntax (UFCS)
auto sum = arr.filter!(a => a < 3);
assert(equal(sum, [ 0, 1, 2 ]));

// Filter with the default predicate
auto nonZeros = arr.filter;
assert(equal(nonZeros, [ 1, 2, 3, 4, 5 ]));

// In combination with concatenation() to span multiple ranges
import mir.ndslice.concatenation;

int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = concatenation(a, b).filter!(a => a > 0);
assert(equal(r, [ 3, 400, 100, 102 ]));

// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = concatenation(c, a, b).filter!(a => cast(int) a != a);
assert(equal(r1, [ 2.5 ]));

N-dimensional filtering

import mir.ndslice.fuse;
import mir.ndslice.topology: byDim, map;

auto matrix =
    [[   3,   -2, 400 ],
     [ 100, -101, 102 ]].fuse;

alias filterPositive = filter!"a > 0";

// filter all elements in the matrix
auto r = filterPositive(matrix);
assert(equal(r, [ 3, 400, 100, 102 ]));

// filter all elements for each row
auto rr = matrix.byDim!0.map!filterPositive;
assert(equal!equal(rr, [ [3, 400], [100, 102] ]));

// filter all elements for each column
auto rc = matrix.byDim!1.map!filterPositive;
assert(equal!equal(rc, [ [3, 100], [], [400, 102] ]));

N-dimensional filtering based on value in specific row/column

import mir.ndslice.fuse;
import mir.ndslice.topology: byDim;

auto matrix =
[[   3,   2, 400 ],
 [ 100, -101, 102 ]].fuse;

// filter row based on value in index 1
auto r1 = matrix.byDim!0.filter!("a[1] > 0");
assert(equal!equal(r1, [ [3, 2, 400] ]));

// filter column based on value in index 1
auto r2 = matrix.byDim!1.filter!("a[1] > 0");
assert(equal!equal(r2, [ [3, 100], [400, 102] ]));

Filter out NaNs

import mir.algorithm.iteration: equal, filter;
import mir.ndslice.slice: sliced;
import std.math.traits: isNaN;

static immutable result1 = [1.0, 2];

double x;
auto y = [1.0, 2, x].sliced;
auto z = y.filter!(a => !isNaN(a));
assert(z.equal(result1));

Filter out NaNs by row and by column

import mir.algorithm.iteration: equal, filter;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: byDim, map;
import std.math.traits: isNaN;

static immutable result1 = [[1.0, 2], [3.0, 4, 5]];
static immutable result2 = [[1.0, 3], [2.0, 4], [5.0]];

double x;
auto y = [[1.0, 2, x], [3.0, 4, 5]].fuse;

// by row
auto z1 = y.byDim!0.map!(filter!(a => !isNaN(a)));
assert(z1.equal!equal(result1));
// by column
auto z2 = y.byDim!1.map!(filter!(a => !isNaN(a)));
assert(z2.equal!equal(result2));

Filter entire rows/columns that have NaNs

import mir.algorithm.iteration: equal, filter;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: byDim, map;
import std.math.traits: isNaN;

static immutable result1 = [[3.0, 4, 5]];
static immutable result2 = [[1.0, 3], [2.0, 4]];

double x;
auto y = [[1.0, 2, x], [3.0, 4, 5]].fuse;

// by row
auto z1 = y.byDim!0.filter!(a => a.all!(b => !isNaN(b)));
assert(z1.equal!equal(result1));
// by column
auto z2 = y.byDim!1.filter!(a => a.all!(b => !isNaN(b)));
assert(z2.equal!equal(result2));

See Also

Filter (higher-order function) Note: User and library code MUST call empty method ahead each call of pair or one of front and popFront methods.

Meta