javascript
exercises
exercises.js⚡javascript
// ============================================
// 17.5 Generators - Exercises
// ============================================
// Exercise 1: Basic Generator
// Create a generator that yields 'a', 'b', 'c'
// Your code here:
// function* abc() {
// ...
// }
// console.log([...abc()]); // ['a', 'b', 'c']
/*
Solution:
function* abc() {
yield 'a';
yield 'b';
yield 'c';
}
console.log([...abc()]); // ['a', 'b', 'c']
*/
// --------------------------------------------
// Exercise 2: Range Generator
// Create a generator that yields numbers from start to end
// Your code here:
// function* range(start, end) {
// ...
// }
// console.log([...range(1, 5)]); // [1, 2, 3, 4, 5]
/*
Solution:
function* range(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
console.log([...range(1, 5)]); // [1, 2, 3, 4, 5]
*/
// --------------------------------------------
// Exercise 3: Countdown Generator
// Create a generator that counts down from n to 1
// Your code here:
// function* countdown(n) {
// ...
// }
// console.log([...countdown(5)]); // [5, 4, 3, 2, 1]
/*
Solution:
function* countdown(n) {
while (n >= 1) {
yield n--;
}
}
console.log([...countdown(5)]); // [5, 4, 3, 2, 1]
*/
// --------------------------------------------
// Exercise 4: Infinite Counter
// Create an infinite generator that counts from 0
// Use it with a take function to get first 5 values
// Your code here:
// function* infiniteCounter() {
// ...
// }
// function take(gen, n) {
// ...
// }
// console.log(take(infiniteCounter(), 5)); // [0, 1, 2, 3, 4]
/*
Solution:
function* infiniteCounter() {
let n = 0;
while (true) {
yield n++;
}
}
function take(iterable, n) {
const result = [];
for (const item of iterable) {
if (result.length >= n) break;
result.push(item);
}
return result;
}
console.log(take(infiniteCounter(), 5)); // [0, 1, 2, 3, 4]
*/
// --------------------------------------------
// Exercise 5: Fibonacci Generator
// Create a generator that yields Fibonacci numbers
// Your code here:
// function* fibonacci() {
// ...
// }
// Using take: first 8 fibonacci numbers should be [1, 1, 2, 3, 5, 8, 13, 21]
/*
Solution:
function* fibonacci() {
let prev = 0, curr = 1;
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
function take(iterable, n) {
const result = [];
for (const item of iterable) {
if (result.length >= n) break;
result.push(item);
}
return result;
}
console.log(take(fibonacci(), 8)); // [1, 1, 2, 3, 5, 8, 13, 21]
*/
// --------------------------------------------
// Exercise 6: Powers Generator
// Create a generator that yields powers of a base (base^0, base^1, base^2, ...)
// Your code here:
// function* powers(base) {
// ...
// }
// console.log(take(powers(2), 5)); // [1, 2, 4, 8, 16]
/*
Solution:
function* powers(base) {
let exp = 0;
while (true) {
yield base ** exp;
exp++;
}
}
console.log(take(powers(2), 5)); // [1, 2, 4, 8, 16]
console.log(take(powers(3), 4)); // [1, 3, 9, 27]
*/
// --------------------------------------------
// Exercise 7: yield* Delegation
// Create a generator that yields 1, 2, then delegates to [3, 4, 5], then yields 6
// Your code here:
// function* combined() {
// ...
// }
// console.log([...combined()]); // [1, 2, 3, 4, 5, 6]
/*
Solution:
function* combined() {
yield 1;
yield 2;
yield* [3, 4, 5];
yield 6;
}
console.log([...combined()]); // [1, 2, 3, 4, 5, 6]
*/
// --------------------------------------------
// Exercise 8: Flatten Generator
// Create a generator that flattens nested arrays using yield*
// Your code here:
// function* flatten(arr) {
// ...
// }
// console.log([...flatten([1, [2, 3], [4, [5, 6]]])]);
// // [1, 2, 3, 4, [5, 6]] (one level only)
/*
Solution:
function* flatten(arr) {
for (const item of arr) {
if (Array.isArray(item)) {
yield* item;
} else {
yield item;
}
}
}
console.log([...flatten([1, [2, 3], [4, [5, 6]]])]); // [1, 2, 3, 4, [5, 6]]
*/
// --------------------------------------------
// Exercise 9: Deep Flatten Generator
// Create a generator that deeply flattens nested arrays
// Your code here:
// function* deepFlatten(arr) {
// ...
// }
// console.log([...deepFlatten([1, [2, [3, [4]]]])]); // [1, 2, 3, 4]
/*
Solution:
function* deepFlatten(arr) {
for (const item of arr) {
if (Array.isArray(item)) {
yield* deepFlatten(item);
} else {
yield item;
}
}
}
console.log([...deepFlatten([1, [2, [3, [4]]]])]); // [1, 2, 3, 4]
console.log([...deepFlatten([[1, 2], [[3], 4], [[[5]]]])]); // [1, 2, 3, 4, 5]
*/
// --------------------------------------------
// Exercise 10: Two-way Communication
// Create a generator that takes input and yields processed output
// Your code here:
// function* echo() {
// let input = yield 'Ready';
// while (input !== 'quit') {
// input = yield `You said: ${input}`;
// }
// return 'Goodbye';
// }
// Test it by calling next() with different values
/*
Solution:
function* echo() {
let input = yield 'Ready';
while (input !== 'quit') {
input = yield `You said: ${input}`;
}
return 'Goodbye';
}
const gen = echo();
console.log(gen.next()); // { value: 'Ready', done: false }
console.log(gen.next('Hello')); // { value: 'You said: Hello', done: false }
console.log(gen.next('World')); // { value: 'You said: World', done: false }
console.log(gen.next('quit')); // { value: 'Goodbye', done: true }
*/
// --------------------------------------------
// Exercise 11: ID Generator
// Create a generator that produces unique IDs with a prefix
// Your code here:
// function* idGenerator(prefix) {
// ...
// }
// const userIds = idGenerator('user');
// console.log(userIds.next().value); // 'user_1'
// console.log(userIds.next().value); // 'user_2'
/*
Solution:
function* idGenerator(prefix) {
let id = 1;
while (true) {
yield `${prefix}_${id++}`;
}
}
const userIds = idGenerator('user');
console.log(userIds.next().value); // 'user_1'
console.log(userIds.next().value); // 'user_2'
console.log(userIds.next().value); // 'user_3'
*/
// --------------------------------------------
// Exercise 12: Filter Generator
// Create a generator that filters values from another iterable
// Your code here:
// function* filter(iterable, predicate) {
// ...
// }
// console.log([...filter([1, 2, 3, 4, 5], x => x % 2 === 0)]); // [2, 4]
/*
Solution:
function* filter(iterable, predicate) {
for (const item of iterable) {
if (predicate(item)) {
yield item;
}
}
}
console.log([...filter([1, 2, 3, 4, 5], x => x % 2 === 0)]); // [2, 4]
*/
// --------------------------------------------
// Exercise 13: Map Generator
// Create a generator that maps values from another iterable
// Your code here:
// function* map(iterable, fn) {
// ...
// }
// console.log([...map([1, 2, 3], x => x * 2)]); // [2, 4, 6]
/*
Solution:
function* map(iterable, fn) {
for (const item of iterable) {
yield fn(item);
}
}
console.log([...map([1, 2, 3], x => x * 2)]); // [2, 4, 6]
console.log([...map(['a', 'b'], s => s.toUpperCase())]); // ['A', 'B']
*/
// --------------------------------------------
// Exercise 14: Zip Generator
// Create a generator that zips two iterables together
// Your code here:
// function* zip(iter1, iter2) {
// ...
// }
// console.log([...zip([1, 2, 3], ['a', 'b', 'c'])]);
// // [[1, 'a'], [2, 'b'], [3, 'c']]
/*
Solution:
function* zip(iter1, iter2) {
const it1 = iter1[Symbol.iterator]();
const it2 = iter2[Symbol.iterator]();
while (true) {
const r1 = it1.next();
const r2 = it2.next();
if (r1.done || r2.done) return;
yield [r1.value, r2.value];
}
}
console.log([...zip([1, 2, 3], ['a', 'b', 'c'])]);
// [[1, 'a'], [2, 'b'], [3, 'c']]
*/
// --------------------------------------------
// Exercise 15: Cycle Generator
// Create a generator that cycles through an array infinitely
// Your code here:
// function* cycle(arr) {
// ...
// }
// const colors = cycle(['red', 'green', 'blue']);
// console.log(colors.next().value); // 'red'
// console.log(colors.next().value); // 'green'
// console.log(colors.next().value); // 'blue'
// console.log(colors.next().value); // 'red' (cycles back)
/*
Solution:
function* cycle(arr) {
while (true) {
yield* arr;
}
}
const colors = cycle(['red', 'green', 'blue']);
console.log(colors.next().value); // 'red'
console.log(colors.next().value); // 'green'
console.log(colors.next().value); // 'blue'
console.log(colors.next().value); // 'red'
console.log(colors.next().value); // 'green'
*/
// --------------------------------------------
// Bonus Exercise: Paginated Data Generator
// Create a generator that simulates paginated API responses
// Your code here:
// function* paginate(data, pageSize) {
// ...
// }
// const pages = paginate([1,2,3,4,5,6,7,8,9,10], 3);
// Each next() should return { page: N, items: [...], hasMore: bool }
/*
Solution:
function* paginate(data, pageSize) {
const totalPages = Math.ceil(data.length / pageSize);
for (let page = 1; page <= totalPages; page++) {
const start = (page - 1) * pageSize;
const end = start + pageSize;
yield {
page,
items: data.slice(start, end),
hasMore: page < totalPages
};
}
}
const pages = paginate([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3);
console.log(pages.next().value); // { page: 1, items: [1, 2, 3], hasMore: true }
console.log(pages.next().value); // { page: 2, items: [4, 5, 6], hasMore: true }
console.log(pages.next().value); // { page: 3, items: [7, 8, 9], hasMore: true }
console.log(pages.next().value); // { page: 4, items: [10], hasMore: false }
*/