Skip to content

feat: add .map() method #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/api/col-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Map for collections.
* @param {function} f Call back function that is called on each item.
* @param {number} start The start index in the collection.
* @param {number} end The end index.
* @param {function} itemFn Item function to create chainable-methods of the item.
* @return {Array} The mapped collection.
* @private
*/
var colMap = function ( f, start, end, itemFn ) {
const result = [];
for ( let k = start; k <= end; k += 1 ) {
// Use relative indexing by adding `start` from `k`.
result.push(f( itemFn( k ), ( k - start ) ));
}
return result;
};

module.exports = colMap;
13 changes: 13 additions & 0 deletions src/api/sel-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Map selected items.
* @param {function} f Call back function that is called on each item.
* @param {number[]} selection Array containing indexes to the selected items.
* @param {function} itemFn Item function to create chainable-methods of the item.
* @return {Array} Array of mapped items.
* @private
*/
var selMap = function ( f, selection, itemFn ) {
return selection.map( ( item, i ) => f( itemFn( item ), i ) );
}; // selMap()

module.exports = selMap;
17 changes: 17 additions & 0 deletions src/doc-v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ var selGetItemAt = require( './api/sel-get-item.js' );
var colEach = require( './api/col-each.js' );
var selEach = require( './api/sel-each.js' );

var colMap = require( './api/col-map.js' );
var selMap = require( './api/sel-map.js' );

// **Filter** for collection & selection.
var colFilter = require( './api/col-filter.js' );
var selFilter = require( './api/sel-filter.js' );
Expand Down Expand Up @@ -185,6 +188,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => selEach( f, selectedTokens, itemToken );
// Map.
api.map = ( f ) => selMap( f, selectedTokens, itemToken );
// Filter.
api.filter = ( f ) => selFilter( f, selectedTokens, itemToken, colSelectedTokens );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
Expand Down Expand Up @@ -213,6 +218,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => colEach( f, start, end, itemToken );
// Map.
api.map = ( f ) => colMap( f, start, end, itemToken );
// Filter.
api.filter = ( f ) => colFilter( f, start, end, itemToken, colSelectedTokens );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
Expand Down Expand Up @@ -275,6 +282,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => selEach( f, selectedEntities, itemEntity );
// Map.
api.map = ( f ) => selMap( f, selectedEntities, itemEntity );
// Filter.
api.filter = ( f ) => selFilter( f, selectedEntities, itemEntity, colSelectedEntities );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
Expand All @@ -299,6 +308,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => colEach( f, 0, entities.length - 1, itemEntity );
// Map.
api.map = ( f ) => colMap( f, 0, entities.length - 1, itemEntity );
// Filter.
api.filter = ( f ) => colFilter( f, 0, entities.length - 1, itemEntity, colSelectedEntities );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
Expand Down Expand Up @@ -357,6 +368,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => selEach( f, selectedCustomEntities, itemCustomEntity );
// Map.
api.map = ( f ) => selMap( f, selectedCustomEntities, itemCustomEntity );
// Filter.
api.filter = ( f ) => selFilter( f, selectedCustomEntities, itemCustomEntity, colSelectedCustomEntities );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
Expand All @@ -381,6 +394,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => colEach( f, 0, customEntities.length - 1, itemCustomEntity );
// Map.
api.map = ( f ) => colMap( f, 0, customEntities.length - 1, itemCustomEntity );
// Filter.
api.filter = ( f ) => colFilter( f, 0, customEntities.length - 1, itemCustomEntity, colSelectedCustomEntities );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
Expand Down Expand Up @@ -438,6 +453,8 @@ var doc = function ( docData, addons ) {
var api = Object.create( null );
// Iterator.
api.each = ( f ) => colEach( f, 0, sentences.length - 1, itemSentence );
// Map.
api.map = ( f ) => colMap( f, 0, sentences.length - 1, itemSentence );
// Item at `k`th index. If `k` is outside valid range, return `undefined` like JS.
api.itemAt = ( k ) => colGetItemAt( k, 0, ( sentences.length - 1 ), itemSentence );
// Length of this collection.
Expand Down
57 changes: 57 additions & 0 deletions test/apiA-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ describe( 'APIs — A', function () {
} );
} );

it( '.map() iterator should go through each sentence', function () {
var result = doc1.sentences().map( ( s ) => s.out() );
expect( result ).to.deep.equal( as1 );

result = doc2.sentences().map( ( s ) => s.out() );
expect( result ).to.deep.equal( as2 );
} );

it( '.itemAt() should return correct sentence item', function () {
const i11 = doc1.sentences().itemAt( 0 );
expect( i11.out() ).to.equal( as1[ 0 ] );
Expand All @@ -189,6 +197,15 @@ describe( 'APIs — A', function () {
} );
} );

it( '.tokens().map() should return retlative token indexes — k', function () {
var result = doc1.sentences().itemAt( 2 ).tokens().map( ( t ) => t.out() );
console.log('🚀 ~ file: apiA-specs.js:202 ~ result:', result, d2s2t);
expect(result).to.deep.equal( d1s2t );

result = doc2.sentences().itemAt( 2 ).tokens().map( ( t ) => t.out() );
expect(result).to.deep.equal( d2s2t );
} );

it( 'sentence.entities() should sentence wise entities correctly', function () {
doc1.sentences().each( ( s, k ) => {
expect( s.entities().out( its.detail ) ).deep.equal( d1SentenceWiseEntities[ k ] );
Expand Down Expand Up @@ -225,6 +242,14 @@ describe( 'APIs — A', function () {
} );
} );

it('.map() should return array of entities with their details', function () {
const result1 = doc1.entities().map((e) => e.out(its.detail));
expect(result1).to.deep.equal(ae1);

const result2 = doc2.entities().map((e) => e.out(its.detail));
expect(result2).to.deep.equal(ae2);
});

it( '.itemAt() should return correct entity item', function () {
const i11 = doc1.entities().itemAt( 5 );
expect( i11.out( its.detail ) ).to.deep.equal( ae1[ 5 ] );
Expand Down Expand Up @@ -283,6 +308,24 @@ describe( 'APIs — A', function () {
expect( e.parentSentence().out() ).to.deep.equal( doc2.sentences().itemAt( es[ k ] ).out() );
});
} );

it('entities().map() --- sentence() should point correct sentence for each entity', function () {
// Maps entity's index to sentence's index.
const es = [ 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2 ];

const expectedSentencesForDoc1 = es.map((sentenceIdx) =>
doc1.sentences().itemAt(sentenceIdx).out()
);
const expectedSentencesForDoc2 = es.map((sentenceIdx) =>
doc2.sentences().itemAt(sentenceIdx).out()
);

const actualSentencesForDoc1 = doc1.entities().map((e) => e.parentSentence().out());
const actualSentencesForDoc2 = doc2.entities().map((e) => e.parentSentence().out());

expect(actualSentencesForDoc1).to.deep.equal(expectedSentencesForDoc1);
expect(actualSentencesForDoc2).to.deep.equal(expectedSentencesForDoc2);
});
} ); // doc.entities() API

describe( 'doc.tokens() API', function () {
Expand Down Expand Up @@ -367,6 +410,20 @@ describe( 'APIs — A', function () {
} );
} );

it('.map() should correctly map filtered numbers', function () {
const mappedF1 = doc1.tokens()
.filter((t) => t.out(its.type) === 'number')
.map((t) => t.out());

expect(mappedF1).to.deep.equal(f1num);

const mappedF2 = doc2.tokens()
.filter((t) => t.out(its.type) === 'number')
.map((t) => t.out());

expect(mappedF2).to.deep.equal(f2num);
});

it( '.itemAt() should return correct item from filtered numebrs', function () {
const i1 = doc1.tokens()
.filter( ( t ) => ( t.out( its.type ) === 'number' ) )
Expand Down
62 changes: 62 additions & 0 deletions test/apiB-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,23 @@ describe( 'APIs — B', function () {
}
} ); // .each() method via .itmAt()

it('.map() method via .itemAt()', function () {
const mappedSentences = [];

for (let i = 0; i < docs.length; i += 1) {
const doc = docs[i];
const sentencesFromMap = doc.sentences().map((s, k) => {
expect(s.out()).to.deep.equal(doc.sentences().itemAt(k).out());
expect(s.out()).to.deep.equal(sentences[i][k]);
return s.out();
});

mappedSentences.push(sentencesFromMap);
}

expect(mappedSentences).to.deep.equal(sentences);
});

it( '.length() method', function () {
for ( let i = 0; i < docs.length; i += 1 ) {
expect( docs[ i ].sentences().length() ).to.equal( sentences[ i ].length );
Expand Down Expand Up @@ -305,6 +322,15 @@ describe( 'APIs — B', function () {
} // for
} ); // .each() method

it('.map() method', function () {
for (let i = 0; i < docs.length; i += 1) {
const doc = docs[i];
const result = doc.entities().map((e) => (e ? e.out() : undefined));

expect(result).to.deep.equal([].concat([], ...entities[i]));
}
});

it( '.filter() method', function () {
expect( docs[ 0 ].entities().filter( dates ).out() ).to.deep.equal( d0[ DATE ] );
expect( docs[ 0 ].entities().filter( cardinals ).out() ).to.deep.equal( d0[ CARDINAL ] );
Expand Down Expand Up @@ -348,6 +374,11 @@ describe( 'APIs — B', function () {
} );
} ); // .each() method

it('.map() method', function () {
const result = selOfCardinals.map((e) => e.out());
expect(result).to.deep.equal(d0[CARDINAL]);
});

it( '.filter() method', function () {
expect( selOfCardinals.filter( ( e ) => ( e.out() === d0[ CARDINAL ][ 0 ] ) ).out() ).to.deep.equal( d0[ CARDINAL ].slice( 0, 1 ) );
} ); // .filter() method
Expand Down Expand Up @@ -420,6 +451,15 @@ describe( 'APIs — B', function () {
} // for
} ); // .each() method

it('.map() method', function () {
for (let i = 0; i < docs.length; i += 1) {
const doc = docs[i];
const result = doc.customEntities().map((e) => (e ? e.out() : undefined));

expect(result).to.deep.equal([].concat([], ...customEntities[i]));
}
});

it( '.filter() method', function () {
expect( docs[ 0 ].customEntities().filter( fighters ).out() ).to.deep.equal( d0ce.fighters );
expect( docs[ 0 ].customEntities().filter( orgs ).out() ).to.deep.equal( d0ce.orgs );
Expand Down Expand Up @@ -463,6 +503,11 @@ describe( 'APIs — B', function () {
} );
} ); // .each() method

it( '.map() method', function () {
const result = selOfFighters.map( ( e ) => e.out());
expect( result ).to.deep.equal( d0ce.fighters );
} ); // .each() method

it( '.filter() method', function () {
expect( selOfFighters.filter( ( e ) => ( e.out() === d0ce.fighters[ 0 ] ) ).out() ).to.deep.equal( d0ce.fighters.slice( 0, 1 ) );
} ); // .filter() method
Expand Down Expand Up @@ -535,6 +580,15 @@ describe( 'APIs — B', function () {
} // for
} ); // .each() method

it('.map() method', function () {
for (let i = 0; i < docs.length; i += 1) {
const doc = docs[i];
const result = doc.tokens().map((t) => (t ? t.out() : undefined));

expect(result).to.deep.equal([].concat([], ...tokens[i]));
}
});

it( '.filter() method', function () {
expect( docs[ 0 ].tokens().filter( words ).out() ).to.deep.equal( d0words );
expect( docs[ 1 ].tokens().filter( words ).out() ).to.deep.equal( d1words );
Expand Down Expand Up @@ -583,6 +637,14 @@ describe( 'APIs — B', function () {
} );
} ); // .each() method

it('.map() method', function () {
const result0 = selOfWords0.map((e) => e.out());
const result1 = selOfWords1.map((e) => e.out());

expect(result0).to.deep.equal(d0words);
expect(result1).to.deep.equal(d1words);
});

it( '.filter() method', function () {
expect( selOfWords0.filter( ( t ) => ( t.out().length < 3 ) ).out() ).to.deep.equal( [ 'by', 'is', 'by' ] );
expect( selOfWords1.filter( ( t ) => ( t.out().length < 3 ) ).out() ).to.deep.equal( [ 'me', 'up', 'on', 'my', 'we' ] );
Expand Down