👔Iterable+ext
extends iterables with custom methods.
Last updated
extends iterables with custom methods.
Last updated
JS⟩ iteration ⟩ iterable ⟩ extension
extends iterables with methods such as filter
, map
, take
, ... etc.
// ⭐️ check if iterable
array.isIterable, // true
object.isIterable, // false
(3).isIterable, // false
// ⭐️ extended methods
'xyz'.forEach(x => log(x)); // x, y, z
'abc'.map(x=>x+2).array, // [ 'a2', 'b2', 'c2' ]
'abcdefg'.take(4).array, // [ 'a', 'b', 'c', 'd' ]
'abcd'.some(x => x > 'm'), // false
// ⭐️ (closed) range
range(0, 3).map(x => x * 2).array, // [0, 2, 4, 6]
range(0, 10).every(x => x < 10), // false
replit ⟩ Iterable.js
// 2023.01.21 - 18:42 (?) first recorded, rename Iterable+ext.js
// ----------------------------------------
//
// ⭐ Iterable + ext
// ----------------------------------------
// - range()
// ----------------------------------------
// 🔸 .isIterable -> boolean
// 🔸 .array -> array
// ----------------------------------------
// 🔹 .filter() -> it
// 🔹 .map() -> it
// 🔹 .take() -> it
// 🔹 .reduce() -> any
// ----------------------------------------
// 🔹 .every() -> boolean
// 🔹 .some() -> boolean
// 🔹 .forEach() -> void
// 🔹 .toArray() -> array
//
Object.defineProperties(Object.prototype, {
// 🔸 obj.isIterable
isIterable: {
get() {
return typeof this[Symbol.iterator] === 'function';
}
},
// 🔸 it.array
array: {
get: function() {
this._checkIterable();
return [...this];
}
},
// obj._iterableValues
_checkIterable: {
value: function() {
// throw error if not iterable
if (!this.isIterable) {
throw new TypeError(`object is not iterable!`);
}
}
},
// 🔹 it.map(f)
map: {
value: function(f) {
this._checkIterable();
const values = this;
// return a mapped iterable
return {
// make iterabor (by using generator function)
*[Symbol.iterator]() {
for (const val of values) yield f(val);
}
}
}
},
// 🔹 it.filter(f)
filter: {
value: function(condition) {
this._checkIterable();
const values = this;
// return a filtered iterable
return {
// make iterabor (by using generator function)
*[Symbol.iterator]() {
for (const val of values) if (condition(val)) yield val;
}
}
}
},
// 🔹 it.take(n)
take: {
value: function(n) {
this._checkIterable();
const values = this;
// return a partial iterable
return {
// make iterabor (by using generator function)
*[Symbol.iterator]() {
for (const val of values) {
if (n > 0) {
n -= 1;
yield val;
} else { return }
}
}
}
}
},
// 🔹 it.forEach(f)
forEach: {
value: function(f) {
this._checkIterable();
for (const val of this) f(val);
}
},
// 🔹 it.reduce()
reduce: {
value: function(...args) {
this._checkIterable();
return [...this].reduce(...args);
}
},
// 🔹 it.toArray()
toArray: {
value: function() {
this._checkIterable();
return [...this];
}
},
// 🔹 it.every(condition)
every: {
value: function(condition) {
this._checkIterable();
for (const val of this) if (!condition(val)) return false;
return true;
}
},
// 🔹 it.some(condition)
some: {
value: function(condition) {
this._checkIterable();
for (const val of this) if (condition(val)) return true;
return false;
}
},
});
// ⭐️ closed range: [start, end]
function range(start, end, step = start < end ? 1 : -1) {
function isInRange(i) {
return (step > 0) ? (start <= i && i <= end) : (end <= i && i <= start);
}
// return an iterable
return {
*[Symbol.iterator]() {
for (let i = start; isInRange(i) ; i += step) {
yield i;
}
}
}
}
// export
// module.exports = { range };
export { range };
replit ⟩ index.js
'use strict'; // ⭐ toggle sloppy/strict mode
const { log } = console;
// ⭐ import
const { logError } = require('./helpers/debug.js'); // functions for debugging
const { isObject } = require('./ext/Object_ext.js'); // extend Object.prototype
const { range } = require('./ext/Iterable.js'); // iterable methods
// ---------------------------------------------------------------------------
const array = [1, 2, 3];
const string = "Hello, world!";
const map = new Map();
const set = new Set();
const object = {};
'xyz'.forEach(x => log(x)); // x, y, z
// ✅ log expressions that never throw
// ---------------------------------------------------------------------------
;[
array.isIterable, // ○
string.isIterable, // ○
map.isIterable, // ○
set.isIterable, // ○
object.isIterable, // ⨉
(3).isIterable, // ⨉
range(0, 10).every(x => x < 10), // ⨉
'abcd'.some(x => x > 'm'), // ⨉
].forEach(x => log(x));
// ✅ list iterables -> array
[
range(1, 3), // [ 1, 2, 3 ]
range(3, -2), // [ 3, 2, 1, 0, -1, -2 ]
range(1, 3, 0.5), // [ 1, 1.5, 2, 2.5, 3 ]
range(0, 10).take(4), // [0, 1, 2, 3]
range(0, 3).map(x => x * 2), // [0, 2, 4, 6]
'abcd', // [ 'a', 'b', 'c', 'd' ]
'abc'.map(x => x + 1), // [ 'a1', 'b1', 'c1' ]
'abcdefg'.filter(x => x < 'd'), // [ 'a', 'b', 'c' ]
'abcdefg'.take(4), // [ 'a', 'b', 'c', 'd' ]
].forEach(x => log(x.array));
// ❗ log expressios that may throw
// ---------------------------------------------------------------------------
[
`object.map(x => x)`, // ⛔ TypeError: 'object' not iterable!
].forEach(exprStr => {
try { log(eval(exprStr)) } catch (e) { logError(e) }
});
range() - half-open range of numbers. (iterable)
obj.isIterable - check if an object is iterable.
Iterator extension (deprecated)
Canvas+ext - use range
.
0: (?)
// ⭐ extending iterables (`it` for short)
// ----------------------------------------
// 🔸 .isIterable -> boolean
// 🔸 .array -> array
// 🔹 .filter() -> it
// 🔹 .map() -> it
// 🔹 .take() -> it
// 🔹 .reduce() -> any
//
// 🔹 .every() -> boolean
// 🔹 .some() -> boolean
// 🔹 .forEach() -> void
// 🔹 .toArray() -> array
// ⭐ helper functions
// ----------------------------------------
// • 🔹 range(start, end, step): iterable
// Iterable (protocol)
Object.defineProperties(Object.prototype, {
// 🔸 obj.isIterable
isIterable: {
get() {
return typeof this[Symbol.iterator] === 'function';
}
},
// 🔸 it.array
array: {
get: function() {
this._checkIterable();
return [...this];
}
},
// obj._iterableValues
_checkIterable: {
value: function() {
// throw error if not iterable
if (!this.isIterable) {
throw new TypeError(`object is not iterable!`);
}
}
},
// 🔹 it.map(f)
map: {
value: function(f) {
this._checkIterable();
const values = this;
// return a mapped iterable
return {
// make iterabor (by using generator function)
*[Symbol.iterator]() {
for (const val of values) yield f(val);
}
}
}
},
// 🔹 it.filter(f)
filter: {
value: function(condition) {
this._checkIterable();
const values = this;
// return a filtered iterable
return {
// make iterabor (by using generator function)
*[Symbol.iterator]() {
for (const val of values) if (condition(val)) yield val;
}
}
}
},
// 🔹 it.take(n)
take: {
value: function(n) {
this._checkIterable();
const values = this;
// return a partial iterable
return {
// make iterabor (by using generator function)
*[Symbol.iterator]() {
for (const val of values) {
if (n > 0) {
n -= 1;
yield val;
} else { return }
}
}
}
}
},
// 🔹 it.forEach(f)
forEach: {
value: function(f) {
this._checkIterable();
for (const val of this) f(val);
}
},
// 🔹 it.reduce()
reduce: {
value: function(...args) {
this._checkIterable();
return [...this].reduce(...args);
}
},
// 🔹 it.toArray()
toArray: {
value: function() {
this._checkIterable();
return [...this];
}
},
// 🔹 it.every(condition)
every: {
value: function(condition) {
this._checkIterable();
for (const val of this) if (!condition(val)) return false;
return true;
}
},
// 🔹 it.some(condition)
some: {
value: function(condition) {
this._checkIterable();
for (const val of this) if (condition(val)) return true;
return false;
}
},
});
// ⭐️ closed range: [start, end]
function range(start, end, step = start < end ? 1 : -1) {
function isInRange(i) {
return (step > 0) ? (start <= i && i <= end) : (end <= i && i <= start);
}
// return an iterable
return {
*[Symbol.iterator]() {
for (let i = start; isInRange(i) ; i += step) {
yield i;
}
}
}
}
// export
module.exports = { range };