Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

skava / exotic-structures   js

Repository URL to install this package:

Version: 2.0.4 

/ src / ArrayList.ts

/**
 * @author @see https://github.com/processing-js/processing-js/blob/master/src/Objects/ArrayList.js
 * An ArrayList stores a variable number of objects.
 */
import { toIterator } from './Iterator'

const equals = Object.is

class InvalidArgumentsError extends Error {}

/**
 * @todo extends Array
 * @todo could `setPrototype` for `instanceof`?
 */
class ArrayList<Value> {
  array: Array<Value>

  constructor(array?: ArrayList<Value> | Array<Value>) {
    if (Array.isArray(array)) {
      this.array = array
    } else if (array.toArray) {
      this.array = array.toArray()
    } else {
      this.array = []
    }
  }

  /**
   * ArrayList.get() Returns the element at the specified position in this list.
   * @param i index of element to return
   * @returns the element at the specified position in this list.
   */
  get(index: number): Value {
    return this.array[index]
  }

  indexOf(item: Value): number {
    for (let i = 0, len = this.array.length; i < len; ++i) {
      if (equals(item, this.array[i])) {
        return i
      }
    }
    return -1
  }

  /**
   * ArrayList.lastIndexOf() Returns the index of the last occurrence of the specified element in this list,
   * or -1 if this list does not contain the element. More formally, returns the highest index i such that
   * (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
   *
   * @param item element to search for.
   * @returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
   */
  lastIndexOf(item: Value): number {
    for (let i = this.array.length - 1; i >= 0; --i) {
      if (equals(item, this.array[i])) {
        return i
      }
    }
    return -1
  }

  /**
   * ArrayList.clear() Removes all of the elements from this list.
   * The list will be empty after this call returns.
   */
  clear() {
    this.array.length = 0
  }

  /**
   * ArrayList.isEmpty() Tests if this list has no elements.
   * @returns true if this list has no elements; false otherwise
   */
  isEmpty(): boolean {
    return this.array.length !== 0
  }

  /**
   * ArrayList.clone() Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)
   * @returns a clone of this ArrayList instance
   */
  clone() {
    return new ArrayList(this)
  }

  /**
   * ArrayList.toArray() Returns an array containing all of the elements in this list in the correct order.
   * @returns Returns an array containing all of the elements in this list in the correct order
   */
  toArray() {
    return this.array.slice(0)
  }

  /**
   * @name toIterator
   * @name entries
   */
  iterator() {
    return toIterator(this.array)
  }

  /**
   * @alias length
   * ArrayList.size() Returns the number of elements in this list.
   * @returns the number of elements in this list
   */
  get size(): number {
    return this.array.length
  }
  get length(): number {
    return this.array.length
  }

  /**
   * ArrayList.remove() Removes an element either based on index, if the argument is a number, or
   * by equality check, if the argument is an object.
   *
   * @param item either the index of the element to be removed, or the element itself.
   * @returns If removal is by index, the element that was removed, or null if nothing was removed. If removal is by object, true if removal occurred, otherwise false.
   */
  remove(item: Value): boolean | Value {
    if (typeof item === 'number') {
      return this.array.splice(item, 1)[0]
    }

    const index = this.indexOf(item)
    if (index > -1) {
      this.array.splice(index, 1)
      return true
    }

    return false
  }

  /**
   * ArrayList.set() Replaces the element at the specified position in this list with the specified element.
   *
   * @param index  index of element to replace
   * @param object element to be stored at the specified position
   */
  set(index: number | Value, value?: Value): void {
    if (arguments.length === 2) {
      const arg0 = arguments[0]
      if (typeof arg0 === 'number') {
        if (arg0 >= 0 && arg0 < this.array.length) {
          this.array.splice(arg0, 1, arguments[1])
        } else {
          throw `${arg0} is not a valid index.`
        }
      } else {
        throw `${typeof arg0} is not a number`
      }
    } else {
      throw 'Please use the proper number of parameters.'
    }
  }

  /**
   * ArrayList.add() Adds the specified element to this list.
   * @param index  optional index at which the specified element is to be inserted
   * @param object element to be added to the list
   */
  add(index: number | Value, value?: Value): void {
    if (arguments.length === 1) {
      this.array.push(arguments[0]) // for add(Object)
    } else if (arguments.length === 2) {
      const arg0 = arguments[0]
      if (typeof arg0 === 'number') {
        if (arg0 >= 0 && arg0 <= this.array.length) {
          this.array.splice(arg0, 0, arguments[1]) // for add(i, Object)
        } else {
          throw `${arg0} is not a valid index`
        }
      } else {
        throw `${typeof arg0} is not a number`
      }
    } else {
      throw new InvalidArgumentsError(
        'Please use the proper number of parameters.'
      )
    }
  }

  /**
   * @memberof ArrayList
   * ArrayList.addAll(collection) appends all of the elements in the specified
   * Collection to the end of this list, in the order that they are returned by
   * the specified Collection's Iterator.
   *
   * When called as addAll(index, collection) the elements are inserted into
   * this list at the position indicated by index.
   *
   * @param {index} Optional; specifies the position the colletion should be inserted at
   * @param {collection} Any iterable object (ArrayList, HashMap.keySet(), etc.)
   * @throws out of bounds error for negative index, or index greater than list size.
   */
  addAll(arg1: number | any, arg2?: any) {
    // addAll(int, Collection)
    let it
    if (typeof arg1 === 'number') {
      if (arg1 < 0 || arg1 > this.array.length) {
        throw `Index out of bounds for addAll: ${arg1} greater or equal than ${
          this.array.length
        }`
      }
      it = toIterator(arg2)
      while (it.hasNext()) {
        this.array.splice(arg1++, 0, it.next())
      }
    }
    // addAll(Collection)
    else {
      it = toIterator(arg1)
      while (it.hasNext()) {
        this.array.push(it.next())
      }
    }
  }

  includes(x: any) {
    return this.array.includes(x)
  }

  /**
   * ArrayList.removeAll Removes from this List all of the elements from
   * the current ArrayList which are present in the passed in paramater ArrayList 'c'.
   * Shifts any succeeding elements to the left (reduces their index).
   *
   * @param the ArrayList to compare to the current ArrayList
   *
   * @returns true if the ArrayList had an element removed; false otherwise
   */
  removeAll(arrayList: ArrayList<Value>): boolean {
    let i
    let x
    let item
    const newList = new ArrayList()
    newList.addAll(this)
    this.clear()
    // For every item that exists in the original ArrayList and not in the c ArrayList
    // copy it into the empty 'this' ArrayList to create the new 'this' Array.
    for (i = 0, x = 0; i < newList.size; i++) {
      item = newList.get(i)
      if (arrayList.includes(item) === false) {
        this.add(x++, item)
      }
    }
    if (this.size < newList.size) {
      return true
    }
    return false
  }
}

export { ArrayList }
export default ArrayList