./src/index.js annotated source

Back to index

        

Identity function used as default values for some later iteration functions

3const identity = x => x;
4

Internally, this representation allows us to chain iterator method calls together. Most of these methods emit an object instance of Iter itself.

8class Iter {
9
10    constructor(iterable) {
11        this.iterable = iterable;
12    }
13

Normal map over an iterator

15    map(fn) {
16        const result = [];
17        for (const member of this.iterable) {
18            result.push(fn(member));
19        }
20        return new Iter(result);
21    }
22

Normal filter from an iterator to an iterable

24    filter(fn = identity) {
25        const result = [];
26        for (const member of this.iterable) {
27            if (fn(member)) {
28                result.push(member);
29            }
30        }
31        return new Iter(result);
32    }
33

Normal left reduce over an iterator

35    reduce(fn, initial) {
36        let result = initial;
37        for (const member of this.iterable) {
38            result = fn(result, member);
39        }
40        return result;
41    }
42

Reports true if every member of the iterable evaluates to truthy value when passed into fn

45    every(fn = identity) {
46        for (const member of this.iterable) {
47            if (!fn(member)) {
48                return false;
49            }
50        }
51        return true;
52    }
53

Reports true if one or more member(s) of the iterable evaluates to truthy value when passed into fn

56    some(fn = identity) {
57        for (const member of this.iterable) {
58            if (fn(member)) {
59                return true;
60            }
61        }
62        return false;
63    }
64

Maps over an iterable and flattens each returned value from fn with depth 1 before concatenating it into the result iterable.

67    flatMap(fn = identity) {
68        const result = this.reduce((cur, next) => cur.concat(fn(next)), []);
69        return new Iter(result);
70    }
71

Partition the list of iterable values into a list of arrays, each with max size maxSize, in order that the members appear in the iterable. e.g. iter([1, 2, 3, 4, 5]).partition(3).toArray() == [[1, 2, 3], [4, 5]]

76    partition(maxSize) {
77        const result = [[]];
78        let idx = 0;
79        let count = 0;
80        for (const member of this.iterable) {
81            result[idx].push(member);
82            count ++;
83            if (count % maxSize === 0) {
84                result.push([]);
85                idx ++;
86            }
87        }
88        return new Iter(result);
89    }
90

Perform a non-stable sort of the iterable list values by some deterministic comparator function that takes each member and returns a value by which each member should be compared. In practice, I've found this more useful than the general comparison-based sort method in JavaScript Array.prototype.sort.

96    sortBy(fn = identity) {
97        const result = [...this.iterable].sort((a, b) => {
98            const fnA = fn(a);
99            const fnB = fn(b);
100            if (fnA < fnB) {
101                return -1;
102            } else if (fnA > fnB) {
103                return 1;
104            } else {
105                return 0;
106            }
107        });
108        return new Iter(result);
109    }
110

Convert whatever iterable value is currently represented by the Iter instance into a flat array.

113    toArray() {
114        return [...this.iterable];
115    }
116

An Iter instance is also a JavaScript iterator, which means we can spread (...iter) and for...of loop over it.

119    [Symbol.iterator]() {
120        const iterable = this.iterable;
121        const gen = function* () {
122            for (const member of iterable) {
123                yield member;
124            }
125        }
126        return gen();
127    }
128
129}
130

Shorthand function to convert an iterator into a chainable Iter object.

133const iter = x => new Iter(x);
134

Helper implementation of range that takes exactly three arguments. The exposed range() API is variadic, but that calls this with deterministic order of arguments.

138function _range(start, end, step) {
139    const result = [];
140    for (let i = start; i < end; i += step) {
141        result.push(i);
142    }
143    return result;
144}
145

range() function whose API is identical to Python range. Returns an Array instance.

147function range(a1, a2, a3) {
148    if (a3 === undefined) {
149        if (a2 === undefined) {
150            return _range(0, a1, 1);
151        } else {
152            return _range(a1, a2, 1);
153        }
154    } else {
155        return _range(a1, a2, a3);
156    }
157}
158

Similar to Python zip(), zips together arrays passed in. zip() is variadic. e.g. zip([1, 2], ['a', 'b']) => [[1, 'a'], [2, 'b']]

161function zip(...arrays) {
162    const arrayCount = arrays.length;
163    const maxLen = Math.max(...arrays.map(a => a.length));
164    const result = new Array(maxLen);
165    for (let i = 0; i < maxLen; i ++) {
166        const x = new Array(arrayCount);
167        for (let j = 0; j < arrayCount; j ++) {
168            x[j] = arrays[j][i];
169        }
170        result[i] = x;
171    }
172    return result;
173}
174

Export those APIs!

176const exposedNames = {
177    iter,
178    range,
179    zip,
180}
181if (typeof window === 'object') {
182    /* istanbul ignore next */
183    window.Ittr = exposedNames;
184}
185if (typeof module === 'object' && module.exports) {
186    module.exports = exposedNames;
187}
188
189