I have written a few classical Python functions in JavaScript. I would appreciate any kind of feedback. The main goal is to learn about JavaScript. For example errors, improvements or existing JavaScript functions that I missed. Additionally, challenges that would be interesting to tackle next would be appreciated.
// Lets start with a simple one:
function list(e){
return Array.from(e);
}
function* zip(...iterables){
const iterators = iterables.map(it => iter(it));
while(true){
const items = iterators.map(it => it.next());
if (items.some(item => item.done)){
return;
}
yield items.map(item => item.value);
}
}
function* map(func, iterable){
for (let elem of iterable){
yield func(elem);
}
}
function* enumerate(iterable, start=0){
let i = start;
for (let elem of iterable){
yield [i++, elem];
}
}
function* iter(object, sentinel){
if (!sentinel){
yield* object;
return;
}
while (true) {
if (typeof object !== "function"){
throw TypeError("iter(object, sentinel): object must be a function")
}
result = object();
if (result === sentinel){
return;
}
yield result;
}
}
function* repeat(object, times){
for (let i = 0; i < times; i += 1) yield object;
}
function* range(start, end=undefined, step=1) {
if(end === undefined){
end = start;
start = 0;
}
for (let i = start; i < end; i += step){
yield i;
}
}
function* cycle(iterable){
saved = [];
for (const e of iterable){
yield e
saved.push(e);
}
while (true) yield* saved;
}
function* islice(iterable, start, end){
if (!end){
end = start;
start = 0;
}
dropfirsts(iterable, start);
yield* firsts(iterable, end-start);
}
function dropfirsts(iterable, n){
for (let i of range(n)){
if (iterable.next().done) return;
}
}
function* firsts(iterable, n){
for (let j of range(n)){
const item = iterable.next();
if (item.done) return;
yield item.value;
}
}
Here are a few examples of how to use it. These are likely not the best.
console.log("Repeating the same value with repeat():")
console.log("\t", list(repeat("x", 5)));
console.log("Pairs of consecutive items from a list using zip():");
const l = [1,2,3,4];
const liter = iter(l);
const literNext = iter(l);
literNext.next();
for (const [x, y] of zip(liter, literNext)) {
console.log("\t", x, y);
}
console.log("Iterator over a callable (with sentinel):");
function f(){
let count = 0;
return () => count+=1;
}
for (const x of iter(f(), 5)){
console.log("\t", x);
}
console.log("Pairing two lists of distinct size with zip():");
for (const [x, y] of zip([1, 2, 3], ["a", "b"])) {
console.log("\t", x, y);
}
console.log("Building two lists from a list of pairs using zip():");
const pairList = [[1,2], [3,4], [5,6], [7,8]];
for (const X of zip(...pairList)) {
console.log("\t", X);
}
console.log("Time two table using zip() and range():");
for (let [i,j] of zip(range(5), range(0, 10, 2))){
console.log("\t", `${i} x 2 = ${j}`);
}
console.log("Enumerate letters from the alphabet with enumerate():");
for (let [i, e] of enumerate(["a", "b", "c"], 1)){
console.log("\t", e, i);
}
console.log("Convert an iterable to an array using list():");
const rangeLen = 5;
console.log("\t", `list(range(${rangeLen})) = `, list(range(rangeLen)));
const squares = list(map(i => i*i, range(5))).join(',');
console.log("Map an iterator using map():");
console.log("\t", `squares = ${squares}`);
const size = 3;
const cycleThrough = [1, 2];
console.log(`Cycle (firsts ${size} elements) of [${cycleThrough}] using cycle():`);
let i = 0;
for (const x of cycle(cycleThrough)){
i += 1;
if (i > size) break;
console.log("\t", x);
}
console.log(`Same using cycle() and islice():`);
for (const x of islice(cycle(cycleThrough), size)){
console.log("\t", x);
}
const start = 1;
console.log(`Same but starting at element ${start}:`);
for (const x of islice(cycle(cycleThrough), start, size+start)){
console.log("\t", x);
}