Skip to main content

array things.js

I’ve been nursing this in a JS Fiddle for a short time now. Just been playing with the LINQ methods and how they would be in JS.

I find OrderBy and GroupBy are interesting.

gist link


var run = function (arr) {
    'use strict';
    var onlyStrings = l('x => typeof x === "string"');
    var onlyNums = l('x => typeof x === "number"');
    var selector = l('x => typeof x');
    var grouper = l('x => typeof x');
    var selectE = l('x => x');
    var evenIndex = l('(x, index) => index % 2 === 0');

    console.clear();
    console.log(l.memory());
    console.log(arr.Select(), arr.Count());
    console.log(arr.First(), arr.Last());
    console.log('First', arr.First(onlyStrings));
    console.log('Last', arr.Last(onlyStrings));
    console.log('Select', arr.Select(selector));
    console.log('Count', arr.Count(onlyStrings));
    console.log('GroupBy', arr.GroupBy(grouper));
    console.log('Sum', arr.Sum(selectE));
    console.log('OrderBy', arr.OrderBy(selectE));
    console.log('OrderByDescending', arr.OrderByDescending(selectE));
    console.log('GroupBy (x, index) => index % 2 === 0', arr.GroupBy(evenIndex));
    console.log('GroupBy (x, index) => index % 2 === 0', arr.GroupBy('(x, index) => index % 2 === 0'));

};

var l = (function () {
    var memory = {};
    var lx = function (lambdaString) {
        if (memory[lambdaString] !== undefined) {
            return memory[lambdaString];
        }

        var oneArg = /([a-zA-Z_][a-zA-Z0-9_]*)\ [\=\-]\>\ (.*)/;
        var multiArgs = /\((([a-zA-Z_][a-zA-Z0-9_]*,?\ ?)+)\)\ [\=\-]\>\ (.*)/;
        var parts = lambdaString.match(oneArg) || lambdaString.match(multiArgs);
        var param = parts[1];
        var body = parts[parts.length - 1];

        body = body.split(/; ?/);
        body = body.map(function (line, i) {
            line = line.replace(/(^ +)|( +$)/, '');
            if (i === (body.length - 1) && !/return/.test(line)) {
                line = 'return ' + line;
            }
            return '  ' + line;
        });
        memory[lambdaString] = new Function(param, body.join(';\n') + ';');
        return memory[lambdaString];
    };
    lx.memory = function () {
        return memory;
    };
    return lx;
})();

var first = function (arr, filter) {
    filter = filter || (function (e) {
        return true;
    });
    var filtered = arr.filter(filter);
    return filtered[0];
};
var last = function (arr, filter) {
    filter = filter || (function (e) {
        return true;
    });
    var filtered = arr.filter(filter);
    return filtered[filtered.length - 1];
};
var select = function (arr, selector) {
    selector = selector || (function (e) {
        return e;
    });
    return arr.map(selector);
};
var count = function (arr, filter) {
    filter = filter || (function (e) {
        return true;
    });
    return arr.filter(filter).length;
};
var groupBy = function (arr, grouper) {
    grouper = grouper || (function (e) {
        return e;
    });
    var grouping = {};
    arr.forEach(function (e, i, a) {
        var groups = this;
        var group = grouper(e, i, a);
        if (groups[group] === undefined) {
            groups[group] = [];
        }
        groups[group].push(e);
    }, grouping);
    return Object.keys(grouping).map(function (e) {
        return grouping[e];
    });
};
var sum = function (arr, selector, initial) {
    initial = initial || 0;
    selector = selector || (function (e) {
        return e;
    });
    return arr.reduce(function (p, c) {
        return p + selector(c);
    }, initial);
};
var orderBy = function (arr, selector) {
    selector = selector || (function (e) {
        return e;
    });
    var compare = function (a, b) {
        var type = typeof selector(a);
        if (type === 'number') {
            return selector(a) - selector(b);
        } else if (type === 'string') {
            return selector(a).localeCompare(selector(b));
        }
    };
    return [].slice.call(arr).sort(compare);
};
var orderByDescending = function (arr, selector) {
    return orderBy(arr, selector).reverse();
};
var take = function (arr, number) {
    return arr.slice(0, number);
};
var skip = function (arr, number) {
    return arr.slice(number);
};
var any = function (arr, condition) {
    if (condition === null) {
        return arr.length > 0;
    }
    return arr.some(condition);
};
var where = function (arr, condition) {
    condition = condition || (function (e) {
        return true;
    });
    return arr.filter(condition);
};

Array.prototype.First = function (filter) {
    if (typeof filter === 'string') {
        filter = l(filter);
    }
    return first(this, filter);
};
Array.prototype.Last = function (filter) {
    if (typeof filter === 'string') {
        filter = l(filter);
    }
    return last(this, filter);
};
Array.prototype.Select = function (selector) {
    if (typeof selector === 'string') {
        selector = l(selector);
    }
    return select(this, selector);
};
Array.prototype.Count = function (filter) {
    if (typeof filter === 'string') {
        filter = l(filter);
    }

    return count(this, filter);
};
Array.prototype.GroupBy = function (grouper) {
    if (typeof grouper === 'string') {
        grouper = l(grouper);
    }
    return groupBy(this, grouper);
};
Array.prototype.Sum = function (selector) {
    if (typeof selector === 'string') {
        selector = l(selector);
    }
    return sum(this, selector);
};
Array.prototype.OrderBy = function (selector) {
    if (typeof selector === 'string') {
        selector = l(selector);
    }
    return orderBy(this, selector);
};
Array.prototype.OrderByDescending = function (selector) {
    if (typeof selector === 'string') {
        selector = l(selector);
    }
    return orderByDescending(this, selector);
};
Array.prototype.Take = function (number) {
    if (typeof number === 'string') {
        number = l(number);
    }
    return take(this, number);
};
Array.prototype.Skip = function (number) {
    if (typeof number === 'string') {
        number = l(number);
    }
    return skip(this, number);
};
Array.prototype.Any = function (condition) {
    if (typeof condition === 'string') {
        condition = l(condition);
    }
    return any(this, condition);
};
Array.prototype.Where = function (condition) {
    if (typeof condition === 'string') {
        condition = l(condition);
    }
    return where(this, condition);
};

run([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'one', 'two', 'three']);