javascript
exercises
exercises.js⚡javascript
// ============================================
// 17.4 Iterators and Iterables - Exercises
// ============================================
// Exercise 1: Manual Iterator Usage
// Get the iterator from the array and call next() three times
const colors = ['red', 'green', 'blue'];
// Your code here:
// const iterator = colors[Symbol.iterator]();
// Call next() and log the results
/*
Solution:
const iterator = colors[Symbol.iterator]();
console.log(iterator.next()); // { value: 'red', done: false }
console.log(iterator.next()); // { value: 'green', done: false }
console.log(iterator.next()); // { value: 'blue', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
*/
// --------------------------------------------
// Exercise 2: Simple Custom Iterable
// Create an iterable object that yields numbers 1 to 3
// Your code here:
// const simpleIterable = {
// [Symbol.iterator]() {
// ...
// }
// };
// for (const num of simpleIterable) {
// console.log(num); // 1, 2, 3
// }
/*
Solution:
const simpleIterable = {
[Symbol.iterator]() {
let current = 1;
return {
next() {
if (current <= 3) {
return { value: current++, done: false };
}
return { done: true };
}
};
}
};
for (const num of simpleIterable) {
console.log(num); // 1, 2, 3
}
*/
// --------------------------------------------
// Exercise 3: Range Class
// Create a Range class that's iterable from start to end
// Your code here:
// class Range {
// constructor(start, end) {
// ...
// }
// [Symbol.iterator]() {
// ...
// }
// }
// const range = new Range(5, 10);
// console.log([...range]); // [5, 6, 7, 8, 9, 10]
/*
Solution:
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
if (current <= end) {
return { value: current++, done: false };
}
return { done: true };
}
};
}
}
const range = new Range(5, 10);
console.log([...range]); // [5, 6, 7, 8, 9, 10]
*/
// --------------------------------------------
// Exercise 4: Countdown Iterator
// Create an iterable that counts down from a number to 1
// Your code here:
// function countdown(start) {
// return {
// [Symbol.iterator]() {
// ...
// }
// };
// }
// console.log([...countdown(5)]); // [5, 4, 3, 2, 1]
/*
Solution:
function countdown(start) {
return {
[Symbol.iterator]() {
let current = start;
return {
next() {
if (current >= 1) {
return { value: current--, done: false };
}
return { done: true };
}
};
}
};
}
console.log([...countdown(5)]); // [5, 4, 3, 2, 1]
*/
// --------------------------------------------
// Exercise 5: Step Range
// Create an iterable that goes from start to end with a step
// Your code here:
// function stepRange(start, end, step) {
// return {
// ...
// };
// }
// console.log([...stepRange(0, 10, 2)]); // [0, 2, 4, 6, 8, 10]
// console.log([...stepRange(1, 10, 3)]); // [1, 4, 7, 10]
/*
Solution:
function stepRange(start, end, step = 1) {
return {
[Symbol.iterator]() {
let current = start;
return {
next() {
if (current <= end) {
const value = current;
current += step;
return { value, done: false };
}
return { done: true };
}
};
}
};
}
console.log([...stepRange(0, 10, 2)]); // [0, 2, 4, 6, 8, 10]
console.log([...stepRange(1, 10, 3)]); // [1, 4, 7, 10]
*/
// --------------------------------------------
// Exercise 6: Character Iterator
// Create an iterable that yields characters in a range (e.g., 'a' to 'e')
// Your code here:
// function charRange(startChar, endChar) {
// ...
// }
// console.log([...charRange('a', 'e')]); // ['a', 'b', 'c', 'd', 'e']
/*
Solution:
function charRange(startChar, endChar) {
const start = startChar.charCodeAt(0);
const end = endChar.charCodeAt(0);
return {
[Symbol.iterator]() {
let current = start;
return {
next() {
if (current <= end) {
return {
value: String.fromCharCode(current++),
done: false
};
}
return { done: true };
}
};
}
};
}
console.log([...charRange('a', 'e')]); // ['a', 'b', 'c', 'd', 'e']
console.log([...charRange('A', 'F')]); // ['A', 'B', 'C', 'D', 'E', 'F']
*/
// --------------------------------------------
// Exercise 7: Take Function
// Create a take function that returns first N items from an iterable
// Your code here:
// function take(iterable, n) {
// ...
// }
// console.log(take([1, 2, 3, 4, 5], 3)); // [1, 2, 3]
/*
Solution:
function take(iterable, n) {
const result = [];
const iterator = iterable[Symbol.iterator]();
for (let i = 0; i < n; i++) {
const { value, done } = iterator.next();
if (done) break;
result.push(value);
}
return result;
}
console.log(take([1, 2, 3, 4, 5], 3)); // [1, 2, 3]
console.log(take([1, 2], 5)); // [1, 2]
*/
// --------------------------------------------
// Exercise 8: Drop Function
// Create a drop function that skips first N items from an iterable
// Your code here:
// function drop(iterable, n) {
// ...
// }
// console.log([...drop([1, 2, 3, 4, 5], 2)]); // [3, 4, 5]
/*
Solution:
function* drop(iterable, n) {
let count = 0;
for (const item of iterable) {
if (count >= n) {
yield item;
}
count++;
}
}
console.log([...drop([1, 2, 3, 4, 5], 2)]); // [3, 4, 5]
*/
// --------------------------------------------
// Exercise 9: Repeat Iterator
// Create an iterable that repeats a value N times
// Your code here:
// function repeat(value, times) {
// ...
// }
// console.log([...repeat('hello', 3)]); // ['hello', 'hello', 'hello']
/*
Solution:
function repeat(value, times) {
return {
[Symbol.iterator]() {
let count = 0;
return {
next() {
if (count < times) {
count++;
return { value, done: false };
}
return { done: true };
}
};
}
};
}
console.log([...repeat('hello', 3)]); // ['hello', 'hello', 'hello']
*/
// --------------------------------------------
// Exercise 10: Cycle Iterator (Infinite)
// Create an iterator that cycles through an array infinitely
// Use with take() to avoid infinite loop
// Your code here:
// function cycle(arr) {
// ...
// }
// const cycled = cycle([1, 2, 3]);
// console.log(take(cycled, 7)); // [1, 2, 3, 1, 2, 3, 1]
/*
Solution:
function cycle(arr) {
return {
[Symbol.iterator]() {
let index = 0;
return {
next() {
const value = arr[index % arr.length];
index++;
return { value, done: false };
}
};
}
};
}
function take(iterable, n) {
const result = [];
for (const item of iterable) {
if (result.length >= n) break;
result.push(item);
}
return result;
}
const cycled = cycle([1, 2, 3]);
console.log(take(cycled, 7)); // [1, 2, 3, 1, 2, 3, 1]
*/
// --------------------------------------------
// Exercise 11: Flatten Iterator
// Create an iterator that flattens nested arrays one level
// Your code here:
// function flatten(arr) {
// ...
// }
// console.log([...flatten([[1, 2], [3, 4], [5]])]); // [1, 2, 3, 4, 5]
/*
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]])]); // [1, 2, 3, 4, 5]
console.log([...flatten([1, [2, 3], 4, [5, 6]])]); // [1, 2, 3, 4, 5, 6]
*/
// --------------------------------------------
// Exercise 12: Zip Iterator
// Create an iterator that combines two arrays into pairs
// Your code here:
// function zip(arr1, arr2) {
// ...
// }
// console.log([...zip([1, 2, 3], ['a', 'b', 'c'])]);
// // [[1, 'a'], [2, 'b'], [3, 'c']]
/*
Solution:
function* zip(arr1, arr2) {
const it1 = arr1[Symbol.iterator]();
const it2 = arr2[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 13: Filter Iterator
// Create an iterator that filters based on a predicate
// 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]
console.log([...filter(['a', 'bb', 'ccc'], s => s.length > 1)]); // ['bb', 'ccc']
*/
// --------------------------------------------
// Exercise 14: Check if Iterable
// Create a function that checks if a value is iterable
// Your code here:
// function isIterable(value) {
// ...
// }
// console.log(isIterable([1, 2, 3])); // true
// console.log(isIterable('hello')); // true
// console.log(isIterable(123)); // false
// console.log(isIterable({ a: 1 })); // false
/*
Solution:
function isIterable(value) {
return value != null && typeof value[Symbol.iterator] === 'function';
}
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable('hello')); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(123)); // false
console.log(isIterable({ a: 1 })); // false
console.log(isIterable(null)); // false
*/
// --------------------------------------------
// Exercise 15: Make Object Iterable
// Make a plain object iterable over its entries
// Your code here:
// function makeIterable(obj) {
// ...
// return obj;
// }
// const person = makeIterable({ name: 'Alice', age: 30 });
// for (const [key, value] of person) {
// console.log(`${key}: ${value}`);
// }
/*
Solution:
function makeIterable(obj) {
obj[Symbol.iterator] = function() {
const entries = Object.entries(this);
let index = 0;
return {
next() {
if (index < entries.length) {
return { value: entries[index++], done: false };
}
return { done: true };
}
};
};
return obj;
}
const person = makeIterable({ name: 'Alice', age: 30, city: 'NYC' });
for (const [key, value] of person) {
console.log(`${key}: ${value}`);
}
// name: Alice
// age: 30
// city: NYC
*/