Implemented a function filter(x, test)

This commit is contained in:
jos 2014-09-04 20:52:51 +02:00
parent d1b96cde4d
commit f1313d8be7
26 changed files with 1291 additions and 836 deletions

View File

@ -1,8 +1,9 @@
# History
## not yet released, version 0.27.1
## not yet released, version 1.0.0
- Implemented a function `filter(x, test)`.
- Removed `math.distribution` for now, needs some rethinking.
- `math.number` can convert units to numbers (requires a second argument)
- Fixed some precedence issues with the range and conversion operators.

View File

@ -1,6 +1,6 @@
{
"name": "mathjs",
"version": "0.27.1-SNAPSHOT",
"version": "1.0.0-SNAPSHOT",
"main": "./dist/math.min.js",
"ignore": [
"coverage",

View File

@ -2,7 +2,7 @@
"name": "mathjs",
"repo": "josdejong/mathjs",
"description": "Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser and offers an integrated solution to work with numbers, big numbers, complex numbers, units, and matrices.",
"version": "0.27.1-SNAPSHOT",
"version": "1.0.0-SNAPSHOT",
"main": "dist/math.min.js",
"keywords": [
"math",

1836
dist/math.js vendored

File diff suppressed because it is too large Load Diff

2
dist/math.map vendored

File diff suppressed because one or more lines are too long

18
dist/math.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -37,6 +37,7 @@
- [exp(x)](exp.md)
- [eye(n)](eye.md)
- [factorial(n)](factorial.md)
- [filter(x, test)](filter.md)
- [fix(x)](fix.md)
- [flatten(x)](flatten.md)
- [floor(x)](floor.md)

View File

@ -132,6 +132,7 @@
## utils
- [clone(x)](clone.md)
- [filter(x, test)](filter.md)
- [forEach(x, callback)](forEach.md)
- [format(value [, precision])](format.md)
- [import(filename | object, override)](import.md)

View File

@ -26,6 +26,11 @@ math.forEach([1, 2, 3], function(value) {
```
## See also
[filter](filter.md),
[map](map.md),
[sort](sort.md)
<!-- Note: This file is automatically generated from source code comments. Changes made in this file will be overridden. -->

View File

@ -33,6 +33,11 @@ math.map([1, 2, 3], function(value) {
```
## See also
[filter](filter.md),
[forEach](forEach.md),
[sort](sort.md)
<!-- Note: This file is automatically generated from source code comments. Changes made in this file will be overridden. -->

View File

@ -0,0 +1,14 @@
module.exports = {
'name': 'filter',
'category': 'Utils',
'syntax': [
'filter(x, test)'
],
'description': 'Filter items in a matrix.',
'examples': [
'isPositive(x) = x > 0',
'filter([6, -2, -1, 4, 3], isPositive)',
'filter([6, -2, 0, 1, 0], x != 0)'
],
'seealso': ['sort', 'map', 'forEach']
};

View File

@ -8,5 +8,5 @@ module.exports = {
'examples': [
'forEach([1, 2, 3], function(val) { console.log(val) })'
],
'seealso': ['unit']
'seealso': ['map', 'sort', 'filter']
};

View File

@ -8,5 +8,5 @@ module.exports = {
'examples': [
'map([1, 2, 3], function(val) { return value * value })'
],
'seealso': []
'seealso': ['filter', 'forEach']
};

View File

@ -8,7 +8,9 @@ module.exports = {
'description': 'Sort the items in a matrix. Compare can be a string "asc" or "desc", or a custom sort function.',
'examples': [
'sort([5, 10, 1])',
'sort(["C", "B", "A", "D"])'
'sort(["C", "B", "A", "D"])',
'sortByLength(a, b) = size(a)[1] - size(b)[1]',
'sort(["Langdon", "Tom", "Sara"], sortByLength)'
],
'seealso': []
'seealso': ['map', 'filter', 'forEach']
};

View File

@ -137,6 +137,7 @@ exports.to = require('./function/units/to');
// functions - utils
exports.clone = require('./function/utils/clone');
exports.map = require('./function/utils/map');
exports.filter = require('./function/utils/filter');
exports.forEach = require('./function/utils/forEach');
exports.format = require('./function/utils/format');
// exports.print = require('./function/utils/print'); // TODO: add documentation for print as soon as the parser supports objects.

View File

@ -0,0 +1,62 @@
'use strict';
var SymbolNode = require('../../expression/node/SymbolNode');
var isBoolean = require('../../util/boolean').isBoolean;
var argsToArray = require('../../util/array').argsToArray;
var ArgumentsError = require('../../error/ArgumentsError');
/**
* Attach a transform function to math.filter
* Adds a property transform containing the transform function.
*
* This transform adds support for equations as test function for math.filter,
* so you can do something like 'filter([3, -2, 5], x > 0)'.
* @param {Object} math
*/
module.exports = function (math) {
var _filter = math.filter;
_filter.transform = function (args, math, scope) {
if (args.length !== 2) {
throw new ArgumentsError('filter', arguments.length, 2);
}
var x = args[0].compile(math).eval(scope);
var test;
if (args[1] instanceof SymbolNode) {
// a function pointer, like filter([3, -2, 5], myTestFunction);
test = args[1].compile(math).eval(scope);
}
else {
// an equation like filter([3, -2, 5], x > 0)
// find an undefined symbol
var _scope = scope || {};
var symbol = args[1]
.find({
type: SymbolNode
})
.filter(function (symbol) {
return !(symbol.name in math) && !(symbol.name in _scope);
})[0];
// create a test function for this equation
var sub = Object.create(_scope);
var eq = args[1].compile(math);
if (symbol) {
var name = symbol.name;
test = function (x) {
sub[name] = x;
return eq.eval(sub);
}
}
else {
throw new Error('No undefined variable found in filter equation');
}
}
return _filter(x, test);
};
math.filter.transform.rawArgs = true;
};

View File

@ -0,0 +1,75 @@
'use strict';
module.exports = function (math) {
var Matrix = require('../../type/Matrix');
/**
* Sort the items in a matrix.
*
* Syntax:
*
* math.filter(x, test)
*
* Examples:
*
* function isPositive (x) {
* return x > 0;
* }
* math.filter([6, -2, -1, 4, 3], isPositive); // returns [6, 4, 3]
*
* math.filter(["23", "foo", "100", "55", "bar"], /[0-9]+/); // returns ["23", "100", "55"]
*
* See also:
*
* forEach, map, sort
*
* @param {Matrix | Array} x A one dimensional matrix or array to filter
* @param {Function | RegExp} test
* A function or regular expression to test items.
* When `test` is a function, it must return a boolean.
* All entries for which `test` returns true are returned.
* @return {Matrix | Array} Returns the filtered matrix.
*/
math.filter = function (x, test) {
if (arguments.length !== 2) {
throw new math.error.ArgumentsError('filter', arguments.length, 2);
}
if (x instanceof Matrix) {
var size = x.size();
if (size.length > 1) {
throw new Error('Only one dimensional matrices supported');
}
return new Matrix(_filter(x.toArray(), test));
}
else if (Array.isArray(x)) {
return _filter(x, test);
}
else {
throw new math.error.UnsupportedTypeError('filter', math['typeof'](x), math['typeof'](compare));
}
};
/**
*
* @param {Array} x
* @param {function | RegExp} test
* @return {Array} Returns the filtered array
* @private
*/
function _filter(x, test) {
if (typeof test === 'function') {
return x.filter(function (entry) {
return test(entry);
});
}
else if (test instanceof RegExp) {
return x.filter(function (entry) {
return test.test(entry);
});
}
else {
throw new TypeError('Function or RegExp expected');
}
}
};

View File

@ -17,6 +17,10 @@ module.exports = function (math) {
* });
* // outputs 1, 2, 3
*
* See also:
*
* filter, map, sort
*
* @param {Matrix | Array} x The matrix to iterate on.
* @param {Function} callback The callback function is invoked with three
* parameters: the value of the element, the index

View File

@ -18,6 +18,10 @@ module.exports = function (math) {
* return value * value;
* }); // returns [1, 4, 9]
*
* See also:
*
* filter, forEach, sort
*
* @param {Matrix | Array} x The matrix to iterate on.
* @param {Function} callback The callback method is invoked with three
* parameters: the value of the element, the index

View File

@ -21,7 +21,11 @@ module.exports = function (math) {
* }
* math.sort(['Langdon', 'Tom', 'Sara'], sortByLength); // returns ['Tom', 'Sara', 'Langdon']
*
* @param {Matrix | Array} x A one dimensional matrix or array to sot
* See also:
*
* filter, forEach, map
*
* @param {Matrix | Array} x A one dimensional matrix or array to sort
* @param {Function | 'asc' | 'desc'} [compare='asc']
* An optional comparator function. The function is called as
* `compare(a, b)`, and must return 1 when a > b, -1 when a < b,

View File

@ -292,6 +292,7 @@ function create (config) {
// functions - utils
require('./function/utils/clone')(math, _config);
require('./function/utils/filter')(math, _config);
require('./function/utils/format')(math, _config);
require('./function/utils/import')(math, _config);
require('./function/utils/map')(math, _config);
@ -310,6 +311,7 @@ function create (config) {
// attach transform functions (for converting one-based indices to zero-based)
require('./expression/transform/concat.transform')(math, _config);
require('./expression/transform/filter.transform')(math, _config);
require('./expression/transform/forEach.transform')(math, _config);
require('./expression/transform/index.transform')(math, _config);
require('./expression/transform/map.transform')(math, _config);

View File

@ -1,3 +1,3 @@
module.exports = '0.27.1-SNAPSHOT';
module.exports = '1.0.0-SNAPSHOT';
// Note: This file is automatically generated when building math.js.
// Changes made in this file will be overwritten.

View File

@ -1,6 +1,6 @@
{
"name": "mathjs",
"version": "0.27.1-SNAPSHOT",
"version": "1.0.0-SNAPSHOT",
"description": "Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser and offers an integrated solution to work with numbers, big numbers, complex numbers, units, and matrices.",
"author": "Jos de Jong <wjosdejong@gmail.com> (https://github.com/josdejong)",
"contributors": [

View File

@ -1084,6 +1084,26 @@ describe('parse', function() {
approx.deepEqual(parseAndEval('to(5.08 cm * 1000, inch)'),
math.unit(2000, 'inch').to('inch'));
});
it('should evaluate function "sort" with a custom sort function', function () {
var scope = {};
parseAndEval('sortByLength(a, b) = size(a)[1] - size(b)[1]', scope);
assert.deepEqual(parseAndEval('sort(["Langdon", "Tom", "Sara"], sortByLength)', scope),
math.matrix(["Tom", "Sara", "Langdon"]));
});
it('should evaluate function "filter" with a custom test function', function () {
var scope = {};
parseAndEval('isPositive(x) = x > 0', scope);
assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], isPositive)', scope),
math.matrix([6, 4, 3]));
});
it('should evaluate function "filter" with a custom test equation', function () {
assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], x > 0)'),
math.matrix([6, 4, 3]));
});
});
});

View File

@ -0,0 +1,49 @@
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index');
describe('filter', function() {
it('should filter an array with a filter function', function() {
function isPositive (x) {
return x > 0;
}
assert.deepEqual(math.filter([6, -2, -1, 4, 3], isPositive), [6, 4, 3]);
});
it('should filter a Matrix with a filter function', function() {
function isPositive (x) {
return x > 0;
}
assert.deepEqual(math.filter(math.matrix([6, -2, -1, 4, 3]), isPositive), math.matrix([6, 4, 3]));
});
it('should filter an array with a regexp', function() {
assert.deepEqual(math.filter(["23", "foo", "100", "55", "bar"], /[0-9]+/), ["23", "100", "55"]);
});
it('should filter a Matrix with a regexp', function() {
assert.deepEqual(math.filter(math.matrix(["23", "foo", "100", "55", "bar"]), /[0-9]+/), math.matrix(["23", "100", "55"]));
});
it('should throw an error if called with a multi dimensional matrix', function() {
function isPositive (x) {
return x > 0;
}
assert.throws(function() { math.filter(math.matrix([[6, -2],[-1, 4]]), isPositive) }, /Only one dimensional matrices supported/);
});
it('should throw an error if called with unsupported type', function() {
assert.throws(function() { math.filter(2, /regexp/) });
assert.throws(function() { math.filter('string', /regexp/) });
assert.throws(function() { math.filter([], 'string') });
assert.throws(function() { math.filter([], {}) });
});
it('should throw an error if called with invalid number of arguments', function() {
assert.throws(function() { math.filter([], /reg/, 'foo') });
assert.throws(function() { math.filter([]) });
});
});

View File

@ -13,6 +13,7 @@ describe('sort', function() {
});
it('should sort a Matrix', function() {
assert.deepEqual(math.sort(math.matrix([5,10,1])), math.matrix([1,5, 10]));
});
it('should sort an array in ascending order', function() {