Skip to content

Commit aa1df18

Browse files
committed
feat: add method subMatrixView
1 parent f077732 commit aa1df18

5 files changed

Lines changed: 131 additions & 0 deletions

File tree

src/abstractMatrix.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var arrayUtils = require('ml-array-utils');
66
var util = require('./util');
77
var MatrixTransposeView = require('./views/transpose');
88
var MatrixRowView = require('./views/row');
9+
var MatrixSubView = require('./views/sub');
910

1011
function abstractMatrix(superCtor) {
1112
if (superCtor === undefined) superCtor = Object;
@@ -1182,6 +1183,10 @@ function abstractMatrix(superCtor) {
11821183
util.checkRowIndex(this, row);
11831184
return new MatrixRowView(this, row);
11841185
}
1186+
1187+
subMatrixView(rowIndices, columnIndices, startColumn, endColumn) {
1188+
return new MatrixSubView(this, rowIndices, columnIndices, startColumn, endColumn);
1189+
}
11851190
}
11861191

11871192
Matrix.prototype.klass = 'Matrix';

src/util.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,48 @@ exports.checkColumnVector = function checkColumnVector(matrix, vector) {
6363
}
6464
return vector;
6565
};
66+
67+
exports.checkIndices = function checkIndices(matrix, rowIndices, columnIndices) {
68+
var rowOut = rowIndices.some(r => {
69+
return r < 0 || r >= matrix.rows;
70+
71+
});
72+
73+
var columnOut = columnIndices.some(c => {
74+
return c < 0 || c >= matrix.columns;
75+
});
76+
77+
if (rowOut || columnOut) {
78+
throw new RangeError('Indices are out of range')
79+
}
80+
81+
if (typeof rowIndices !== 'object' || typeof columnIndices !== 'object') {
82+
throw new TypeError('Unexpected type for row/column indices');
83+
}
84+
if (!Array.isArray(rowIndices)) rowIndices = Array.from(rowIndices);
85+
if (!Array.isArray(columnIndices)) rowIndices = Array.from(columnIndices);
86+
87+
return {
88+
row: rowIndices,
89+
column: columnIndices
90+
};
91+
};
92+
93+
exports.checkRange = function checkRange(matrix, startRow, endRow, startColumn, endColumn) {
94+
if (arguments.length !== 5) throw new TypeError('Invalid argument type');
95+
var notAllNumbers = Array.from(arguments).slice(1).some(function (arg) {
96+
return typeof arg !== 'number';
97+
});
98+
if (notAllNumbers) throw new TypeError('Invalid argument type');
99+
if (startRow > endRow || startColumn > endColumn || startRow < 0 || startRow >= matrix.rows || endRow < 0 || endRow >= matrix.rows || startColumn < 0 || startColumn >= matrix.columns || endColumn < 0 || endColumn >= matrix.columns) {
100+
throw new RangeError('Submatrix indices are out of range');
101+
}
102+
};
103+
104+
exports.getRange = function getRange(from, to) {
105+
var arr = new Array(to - from + 1);
106+
for (var i = 0; i < arr.length; i++) {
107+
arr[i] = from + i;
108+
}
109+
return arr;
110+
};

src/views/base.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ class BaseView extends abstractMatrix() {
99
this.rows = rows;
1010
this.columns = columns;
1111
}
12+
13+
// Native array methods should return instances of Array, not Matrix
14+
static get[Symbol.species]() {
15+
return require('../matrix');
16+
}
1217
}
1318

1419
module.exports = BaseView;

src/views/sub.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
3+
var BaseView = require('./base');
4+
var util = require('../util');
5+
6+
class MatrixSubView extends BaseView {
7+
constructor(matrix, rowIndices, columnIndices, startColumn, endColumn) {
8+
var rowI, columnI;
9+
if(typeof rowIndices === 'number') {
10+
var startRow = rowIndices, endRow = columnIndices;
11+
util.checkRange(matrix, startRow, endRow, startColumn, endColumn);
12+
rowI = util.getRange(startRow, endRow);
13+
columnI = util.getRange(startColumn, endColumn);
14+
} else {
15+
var indices = util.checkIndices(matrix, rowIndices, columnIndices);
16+
rowI = indices.row;
17+
columnI = indices.column;
18+
}
19+
super(matrix, rowI.length, columnI.length);
20+
this.rowIndices = rowI;
21+
this.columnIndices = columnI;
22+
}
23+
24+
set(rowIndex, columnIndex, value) {
25+
this.matrix.set(this.rowIndices[rowIndex], this.columnIndices[columnIndex] , value);
26+
return this;
27+
}
28+
29+
get(rowIndex, columnIndex) {
30+
return this.matrix.get(this.rowIndices[rowIndex], this.columnIndices[columnIndex]);
31+
}
32+
}
33+
34+
module.exports = MatrixSubView;

test/views/sub.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
3+
var Matrix = require('../..');
4+
5+
describe('Sub view', function () {
6+
it('should correctly remap coordinates', function () {
7+
var m = Matrix.ones(5, 8);
8+
var msv = m.subMatrixView([1,2], [2,1]);
9+
10+
m.get(1, 2).should.equal(1);
11+
msv.set(0, 0, 5);
12+
m.get(1, 2).should.equal(5);
13+
14+
m.get(2,1).should.equal(1);
15+
m.set(2,1, 10);
16+
msv.get(1,1).should.equal(10);
17+
18+
msv = m.subMatrixView(3,4,6,7);
19+
m.get(4,7).should.equal(1);
20+
msv.set(1, 1, 20);
21+
m.get(4,7).should.equal(20);
22+
});
23+
24+
it('should throw when wrong arguments or range', function () {
25+
var m = Matrix.ones(2,2);
26+
(function () {
27+
m.subMatrixView(0,1);
28+
}).should.throw(TypeError);
29+
30+
(function () {
31+
m.subMatrixView(0,1,0,2);
32+
}).should.throw(RangeError);
33+
34+
(function () {
35+
m.subMatrixView([1,1,2], [0,2]);
36+
}).should.throw(RangeError);
37+
38+
(function () {
39+
m.subMatrixView([1,1,2])
40+
}).should.throw(TypeError);
41+
});
42+
});

0 commit comments

Comments
 (0)