Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Finally happy to see that now we can have iterators and generators. I also need to try to have private properties too so that we have well encapsulated data structures and I see that there are Proxies and Symbols which could help me do that.

Utils:

export const isDefAndNotNull = object =>
  object !== undefined && object !== null;

export const isIterable = object =>
  isDefAndNotNull(object) && typeof object[Symbol.iterator] === 'function';

Code:

import {isDefAndNotNull, isIterable} from "./Utils";

function *reverseArrayGenerator(arr) {
  let i = arr.length;
  while(--i >= 0) {
    yield arr[i];
  }
}

const data = Symbol("data");

export default class {
  constructor(iterable) {
    this[data] = [];
    if (isIterable(iterable)) {
      for (let item of iterable) {
        this.push(item);
      }
    }
  }

  peek() {
    return this[data].slice(-1)[0];
  }

  push(item) {
    this[data].push(item);
  }

  pop() {
    return this[data].pop();
  }

  isEmpty() {
    return this[data].length === 0;
  }

  size() {
    return this[data].length;
  }

  toString() {
    let res = [];
    for (let item of this) {
      res.push(item);
    }
    return JSON.stringify(res.join(' '));
  }

  [Symbol.iterator]() {
    return reverseArrayGenerator(this[data]);
  }
}

Test:

import {strictEqual as equal} from "assert";
import Stack from "../src/Stack";

suite("Stack", () => {
  test("without iterator", () => {
    const s = new Stack();
    s.push(1);
    equal(s.size(), 1);
    equal(s.pop(), 1);
    equal(s.size(), 0);
  });

  test("with iterator", () => {
    let s = new Stack([1, 2, 3]);
    equal(s.size(), 3);
    s = new Stack('hello');
    equal(s.size(), 5);
    s = new Stack([{name: 'Foo'}, {name: 'Bar'}]);
    equal(s.size(), 2);
  });

  test("peek", () => {
    let s = new Stack([1, 2, 3]);
    equal(s.peek(), 3);
    s.pop();
    equal(s.peek(), 2);
  });

  test("iterator", () => {
    const s = new Stack([1, 2, 3]);
    let i = 3;
    for(let item of s) {
      equal(item, i);
      i--;
    }
  });
});

Reference: http://algs4.cs.princeton.edu/13stacks/Stack.java.html

share|improve this question

Just so you know, JS arrays are essentially stacks (they have push and pop). So I'm not sure why you need to reimplement a stack in JS.

if (isIterable(iterable)) {
  for (let item of iterable) {
    this.push(item);
  }
}

JS has the spread operator. Additionally, array.push actually accepts more than one argument, pushing each item in order. This means you can do this:

const anotherArray = [1,2,3];

// Choose your weapon
array.push(1); array.push(2); array.push(3);
array.push(1,2,3);
Array.prototype.push.apply(array, anotherArray);
array.push(...anotherArray);

This assumes an array as the argument though. Other iterables might need the for-of.

share|improve this answer
    
First thing first, the concept of ADT isn't implementation language specific, they provide us a interface to speak and here I have implemented that interface, like what is the size of the stack? is the stack empty? I forgot the bound check otherwise it would shout at the user and give them StackUnderflow error. What about pop or peek? do you think its a good idea to re-implement it again and again for any specific problem? – CodeYogi 2 days ago
    
Regarding Iterable I don't think that I would go for spread operator because I need to take different path for array and other iterable like Set. – CodeYogi 2 days ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.