1import { vectorToArray } from './vectorToArray';
2import { Vector } from '../types';
3
4/** @public */
5export abstract class FunctionalVector<T = any> implements Vector<T>, Iterable<T> {
6  abstract get length(): number;
7
8  abstract get(index: number): T;
9
10  // Implement "iterator protocol"
11  *iterator() {
12    for (let i = 0; i < this.length; i++) {
13      yield this.get(i);
14    }
15  }
16
17  // Implement "iterable protocol"
18  [Symbol.iterator]() {
19    return this.iterator();
20  }
21
22  forEach(iterator: (row: T) => void) {
23    return vectorator(this).forEach(iterator);
24  }
25
26  map<V>(transform: (item: T, index: number) => V) {
27    return vectorator(this).map(transform);
28  }
29
30  filter(predicate: (item: T) => boolean): T[] {
31    return vectorator(this).filter(predicate);
32  }
33
34  toArray(): T[] {
35    return vectorToArray(this);
36  }
37
38  toJSON(): any {
39    return this.toArray();
40  }
41}
42
43/**
44 * Use functional programming with your vector
45 */
46export function vectorator<T>(vector: Vector<T>) {
47  return {
48    *[Symbol.iterator]() {
49      for (let i = 0; i < vector.length; i++) {
50        yield vector.get(i);
51      }
52    },
53
54    forEach(iterator: (row: T) => void) {
55      for (let i = 0; i < vector.length; i++) {
56        iterator(vector.get(i));
57      }
58    },
59
60    map<V>(transform: (item: T, index: number) => V) {
61      const result: V[] = [];
62      for (let i = 0; i < vector.length; i++) {
63        result.push(transform(vector.get(i), i));
64      }
65      return result;
66    },
67
68    /** Add a predicate where you return true if it should *keep* the value */
69    filter(predicate: (item: T) => boolean): T[] {
70      const result: T[] = [];
71      for (const val of this) {
72        if (predicate(val)) {
73          result.push(val);
74        }
75      }
76      return result;
77    },
78  };
79}
80