sangja
Version:
JavaScript data structures library
175 lines (154 loc) • 4.13 kB
JavaScript
const Utils = require('./utils');
/**
* @class
* @memberof sangja
*/
class Stack {
/**
* Creates a new Stack.
* Iterable parameter is optional.
* @constructor
* @param {iterable} [iterable] - Iterator for initialize the stack.
* @throws {TypeError} When given parameter is not stack.
*/
constructor(iterable = []) {
if (!Utils.isIterable(iterable)) {
throw TypeError();
}
this._stack = [...iterable];
}
/**
* Add value at the top of the stack.
* @param {*} value - The value to push to the stack.
*/
push(value) {
this._stack.push(value);
}
/**
* Add values in the given iterator at the top of the stack.
* @param {iterable} iterable - The iterable values to push to the stack.
*/
pushAll(iterable) {
[...iterable].forEach(v => this._stack.push(v));
}
/**
* Removes the top of the stack and returns the value at the top of the stack.
* @returns {*} The value at the top of the stack. If empty, return undefined.
*/
pop() {
if (this._stack.length === 0) {
return undefined;
}
return this._stack.pop();
}
/**
* Returns the value at the top of the stack without changing the state of the stack.
* @returns {*} The value at the top of the stack. If empty, return undefined.
*/
top() {
if (this._stack.length === 0) {
return undefined;
}
return this._stack[this._stack.length - 1];
}
/**
* Removes all values in the stack.
*/
clear() {
this._stack = [];
}
/**
* Returns the number of elements in the stack.
* @returns {number} The number of elements in the stack.
*/
size() {
return this._stack.length;
}
/**
* Returns whether the stack is empty.
* @returns {boolean} True if the stack is empty.
*/
isEmpty() {
return this._stack.length === 0;
}
/**
* For each values in the stack, execute the given procedure f.<br>
* *Executing order is top to bottom*
* @param {function} f - Procedure to execute
*/
forEach(f) {
for (let i = this._stack.length - 1; i >= 0; i -= 1) {
f(this._stack[i]);
}
}
/**
* Returns a stack whose values are mapped with given function f.
* @param {function} f - Function to map values
* @return {Stack} Stack([mapped values])
*/
map(f) {
const stack = new Stack();
stack._stack = this._stack.map(f);
return stack;
}
/**
* Returns a stack whose values are mapped with given function f and flattened.
* @param {function} f - Function (this.value) => iterable
* @return {Stack} Stack([mapped and flattened values])
*/
flatMap(f) {
const stack = new Stack();
// [...this._stack.map(f)].forEach(arr => arr.forEach(v => stack.push(v)));
this._stack.map(f).forEach(arr => stack.pushAll(arr));
return stack;
}
/**
* Returns a stack whose values are filtered with given predicate f.
* @param {function} f - Predicate (this.value) => boolean
* @return {Stack} Stack([filtered values])
*/
filter(f) {
const stack = new Stack();
stack._stack = this._stack.filter(f);
return stack;
}
/**
* Returns a stack whose values are reversed in order.
* @return {Stack} Stack([reversed values])
*/
reversed() {
return new Stack(this);
}
/**
* If any of containing values satisfies given f, return true.
* If none of values satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
some(f) {
return this._stack.some(f);
}
/**
* If all of containing values satisfies given f or not contain any value, return true.
* If any of value doesn't satisfy f, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
every(f) {
return this._stack.every(f);
}
/**
* If contains given value v, return true.
* @param {*} v
* @returns {boolean}
*/
includes(v) {
return this._stack.includes(v);
}
* [Symbol.iterator]() {
for (let i = this._stack.length - 1; i >= 0; i -= 1) {
yield this._stack[i];
}
}
}
module.exports = Stack;