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 / FlatArrayPairs.ts

// @todo
import { isEven, isOdd, zip } from 'chain-able-boost'
// const isEven = require('../math/even')
// const isOdd = require('../math/odd')
// const zip = require('../util/zip')

// @TODO cannot import toFlatPairs here because circular :-/
// @TODO move to deps
// @TODO can use .findIndex too
const findIndexPlusOne = (needle, haystack) => haystack.indexOf(needle) + 1
const atIndexPlusOne = (needle, haystack) =>
  haystack[findIndexPlusOne(needle, haystack)]
const findIndexMinusOne = (needle, haystack) => haystack.indexOf(needle) - 1
const atIndexMinusOne = (needle, haystack) =>
  haystack[findIndexMinusOne(needle, haystack)]

/**
 * @desc allows any key val
 * @type {Array}
 * @HACK @FIXME @TODO
 * - BABEL HATES EXTENDING NATIVES
 * - Compiled with ts | buble to enable it
 * - you've been able to do this for years
 *
 * @TODO Set
 * https://stackoverflow.com/questions/7069052/how-to-obtain-index-of-a-given-set-element-without-iteration
 */
interface Pair<Key, Value> extends Array<[Key, Value]> {}

/**
 * @todo use mobx array?
 */
type IndexPredicate = (x: number) => boolean
interface FlatArrayPairs<Key, Value> {
  type: any
  typed(type): void

  has(key: Key): boolean
  set(key: Key, value: Value): this
  add(key: Key, value: Value): this
  add(key: [Key, Value]): this
  addPair(pair: [Key, Value] | [Key, Value][]): this

  get(key: Key): Value | undefined
  getKey(value: Value): Key | undefined

  toPairs(): Pair<Key, Value>[]

  allocate: Array<undefined>
  /* protected */
  half(indexPredicate: IndexPredicate): Array<Key | Value>
  keys(): Key[]
  values(): Value[]
}

class FlatPairArray<Key, Value> extends Array
  implements FlatArrayPairs<Key, Value> {
  type: any

  typed(type) {
    this.type = type
    return this
  }
  has(key: Key) {
    return this.indexOf(key) !== -1
  }
  // push(key, value) {
  //   return this.set(key, value)
  // }
  set(key: Key, value: Value): this {
    if (this.has(key)) return this
    super.push(key)
    super.push(value)
    return this
  }
  add(key: Key | [Key, Value], value?: Value): this {
    if (value === undefined && Array.isArray(key) === true) {
      super.push(key as [Key, Value])
      return this
    } else {
      return this.set(key as Key, value as Value)
    }
  }
  get(key: Key): Value | undefined {
    return atIndexPlusOne(key, this)
  }
  getKey(value: Value): Key | undefined {
    return atIndexMinusOne(value, this)
  }

  /**
   * @param indexPredicate match current index (isEven, isOdd, etc)
   * @return keys or values
   *
   * @example
   *    const pairs = new FlatPairArray([ [1, '2'], [3, '4'] ])
   *    //=> [1, '2', 3, '4']
   *
   *    pairs.half(isEven)
   *    //=> []
   */
  half(indexPredicate: IndexPredicate): Key[] | Value[] {
    const preAllocated = new Array(this.length / 2)
    for (let index = 0; index < this.length; index++) {
      if (indexPredicate(index)) {
        preAllocated[index] = this[index]
      }
    }
    return preAllocated
  }

  toPairs(): Pair<Key, Value>[] {
    const keys = this.keys()
    const values = this.values()
    return zip(keys, values)
  }

  get allocate(): Array<undefined> {
    return new Array(this.length)
  }

  /**
   * @name concatPair?
   *
   * @example
   *    new FlatPairArray().(pair: [Key, Value] | [Key, Value][]([ [1, '2'], [3, '4'] ])
   *    //=> [1, '2', 3, '4']
   */
  addPair(pair: [Key, Value] | [Key, Value][]): this {
    for (let index = 0; index < pair.length; index++) {
      const [key, value] = pair[index] as [Key, Value]
      this.push(key)
      this.push(value)
    }

    return this
  }

  keys(): Key[] & IterableIterator<number> {
    return this.half(isOdd) as Key[] & IterableIterator<number>
  }
  values(): Value[] & IterableIterator<number> {
    return this.half(isEven) as Value[] & IterableIterator<number>
  }
}

export {
  FlatPairArray as FlatArrayPairs,
  FlatPairArray as FlatPairArrays,
  FlatPairArray,
  findIndexPlusOne,
  atIndexPlusOne,
  findIndexMinusOne,
  atIndexMinusOne,
}
export default FlatPairArray