javascript

exercises

exercises.js
/**
 * =====================================================
 * 5.7 HIGHER-ORDER FUNCTIONS - EXERCISES
 * =====================================================
 * Practice with functions that take/return functions
 */

/**
 * Exercise 1: Basic map()
 *
 * Use map to transform the array.
 */
console.log('Exercise 1: Basic map()');

const numbers = [1, 2, 3, 4, 5];

// TODO: Create an array of squares
// const squares = numbers.map(???);
// console.log(squares);  // [1, 4, 9, 16, 25]

// TODO: Create an array of strings
// const strings = numbers.map(???);
// console.log(strings);  // ["1", "2", "3", "4", "5"]

/**
 * Exercise 2: map() with Objects
 *
 * Extract and transform data from objects.
 */
console.log('\nExercise 2: map() with Objects');

const users = [
  { firstName: 'Alice', lastName: 'Smith', age: 25 },
  { firstName: 'Bob', lastName: 'Jones', age: 30 },
  { firstName: 'Charlie', lastName: 'Brown', age: 35 },
];

// TODO: Extract full names
// const fullNames = users.map(???);
// console.log(fullNames);  // ["Alice Smith", "Bob Jones", "Charlie Brown"]

// TODO: Create summary objects { name, age }
// const summaries = users.map(???);
// console.log(summaries);

/**
 * Exercise 3: filter()
 *
 * Filter arrays based on conditions.
 */
console.log('\nExercise 3: filter()');

const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// TODO: Get odd numbers
// const odds = nums.filter(???);
// console.log(odds);  // [1, 3, 5, 7, 9]

// TODO: Get numbers greater than 5
// const large = nums.filter(???);
// console.log(large);  // [6, 7, 8, 9, 10]

/**
 * Exercise 4: filter() with Objects
 *
 * Filter objects based on properties.
 */
console.log('\nExercise 4: filter() with Objects');

const products = [
  { name: 'Laptop', price: 999, inStock: true },
  { name: 'Phone', price: 699, inStock: false },
  { name: 'Tablet', price: 499, inStock: true },
  { name: 'Watch', price: 299, inStock: true },
];

// TODO: Get products in stock
// const available = products.filter(???);

// TODO: Get products under $500 that are in stock
// const cheapAvailable = products.filter(???);

/**
 * Exercise 5: reduce() - Sum and Count
 *
 * Use reduce to calculate values.
 */
console.log('\nExercise 5: reduce()');

const values = [10, 20, 30, 40, 50];

// TODO: Calculate sum
// const sum = values.reduce(???);
// console.log(sum);  // 150

// TODO: Calculate average
// const avg = values.reduce(???) / values.length;
// console.log(avg);  // 30

/**
 * Exercise 6: reduce() - Object Transformation
 *
 * Transform array to object.
 */
console.log('\nExercise 6: reduce() - Object Transformation');

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];

// TODO: Count occurrences
// const counts = fruits.reduce(???);
// console.log(counts);  // { apple: 3, banana: 2, orange: 1 }

const items = [
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
  { id: 3, name: 'Item 3' },
];

// TODO: Create lookup object by id
// const lookup = items.reduce(???);
// console.log(lookup);  // { 1: { id: 1, name: "Item 1" }, ... }

/**
 * Exercise 7: find() and findIndex()
 *
 * Find specific elements.
 */
console.log('\nExercise 7: find() and findIndex()');

const employees = [
  { id: 101, name: 'Alice', department: 'Engineering' },
  { id: 102, name: 'Bob', department: 'Sales' },
  { id: 103, name: 'Charlie', department: 'Engineering' },
];

// TODO: Find employee with id 102
// const bob = employees.find(???);

// TODO: Find index of first Engineering employee
// const engIndex = employees.findIndex(???);

/**
 * Exercise 8: some() and every()
 *
 * Test array conditions.
 */
console.log('\nExercise 8: some() and every()');

const scores = [75, 82, 90, 68, 95];

// TODO: Check if any score is perfect (100)
// const hasPerfect = scores.some(???);

// TODO: Check if all scores are passing (>= 60)
// const allPassing = scores.every(???);

/**
 * Exercise 9: Method Chaining
 *
 * Chain methods for complex operations.
 */
console.log('\nExercise 9: Method Chaining');

const transactions = [
  { type: 'credit', amount: 1000 },
  { type: 'debit', amount: 200 },
  { type: 'credit', amount: 500 },
  { type: 'debit', amount: 100 },
  { type: 'credit', amount: 250 },
];

// TODO: Get total of credits
// const totalCredits = transactions
//     .filter(???)
//     .map(???)
//     .reduce(???);
// console.log(totalCredits);  // 1750

/**
 * Exercise 10: sort()
 *
 * Sort arrays using comparison functions.
 */
console.log('\nExercise 10: sort()');

const people = [
  { name: 'Charlie', age: 35 },
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
];

// TODO: Sort by age (ascending)
// const byAge = [...people].sort(???);

// TODO: Sort by name (alphabetical)
// const byName = [...people].sort(???);

// =====================================================
// INTERMEDIATE EXERCISES
// =====================================================

/**
 * Exercise 11: Custom Higher-Order Function
 *
 * Create a repeat function.
 */
console.log('\nExercise 11: Custom Higher-Order Function');

function repeat(n, action) {
  // TODO: Execute action n times with index as argument
}

// Test:
// repeat(3, i => console.log(`Iteration ${i}`));
// Should print: Iteration 0, Iteration 1, Iteration 2

/**
 * Exercise 12: Function Factory
 *
 * Create a function that returns functions.
 */
console.log('\nExercise 12: Function Factory');

function createGreeter(greeting) {
  // TODO: Return a function that takes name and returns greeting message
}

// Test:
// const sayHello = createGreeter("Hello");
// const sayHi = createGreeter("Hi");
// console.log(sayHello("Alice"));  // "Hello, Alice!"
// console.log(sayHi("Bob"));       // "Hi, Bob!"

/**
 * Exercise 13: Implement myMap
 *
 * Create your own map function.
 */
console.log('\nExercise 13: Implement myMap');

function myMap(array, transform) {
  // TODO: Implement map functionality
}

// Test:
// console.log(myMap([1, 2, 3], n => n * 2));  // [2, 4, 6]

/**
 * Exercise 14: Implement myFilter
 *
 * Create your own filter function.
 */
console.log('\nExercise 14: Implement myFilter');

function myFilter(array, predicate) {
  // TODO: Implement filter functionality
}

// Test:
// console.log(myFilter([1, 2, 3, 4, 5], n => n > 2));  // [3, 4, 5]

/**
 * Exercise 15: Pipe Function
 *
 * Create a pipe function that chains function calls.
 */
console.log('\nExercise 15: Pipe Function');

function pipe(...fns) {
  // TODO: Return function that applies fns left to right
}

// Test:
// const process = pipe(
//     n => n + 1,
//     n => n * 2,
//     n => n - 3
// );
// console.log(process(5));  // ((5 + 1) * 2) - 3 = 9

// =====================================================
// ADVANCED EXERCISES
// =====================================================

/**
 * Bonus Exercise 1: Group By
 *
 * Create a groupBy function.
 */
console.log('\nBonus 1: Group By');

function groupBy(array, keyFn) {
  // TODO: Group array elements by key function result
}

// Test:
// const grouped = groupBy(
//     [{ type: 'a', val: 1 }, { type: 'b', val: 2 }, { type: 'a', val: 3 }],
//     item => item.type
// );
// console.log(grouped);
// { a: [{ type: 'a', val: 1 }, { type: 'a', val: 3 }], b: [...] }

/**
 * Bonus Exercise 2: Compose
 *
 * Create a compose function (right to left).
 */
console.log('\nBonus 2: Compose');

function compose(...fns) {
  // TODO: Return function that applies fns right to left
}

// Test:
// const calc = compose(
//     n => n - 3,
//     n => n * 2,
//     n => n + 1
// );
// console.log(calc(5));  // (((5) + 1) * 2) - 3 = 9

/**
 * Bonus Exercise 3: Memoize
 *
 * Create a memoize function for caching results.
 */
console.log('\nBonus 3: Memoize');

function memoize(fn) {
  // TODO: Return memoized version of fn
}

// Test:
// let callCount = 0;
// const expensiveFn = memoize((n) => {
//     callCount++;
//     return n * 2;
// });
// expensiveFn(5);  // Computed
// expensiveFn(5);  // Cached
// console.log(callCount);  // 1

/**
 * Bonus Exercise 4: Flatten
 *
 * Flatten nested arrays to specified depth.
 */
console.log('\nBonus 4: Flatten');

function flatten(array, depth = 1) {
  // TODO: Flatten array to specified depth
}

// Test:
// console.log(flatten([1, [2, [3, [4]]]], 1));  // [1, 2, [3, [4]]]
// console.log(flatten([1, [2, [3, [4]]]], 2));  // [1, 2, 3, [4]]
// console.log(flatten([1, [2, [3, [4]]]], Infinity));  // [1, 2, 3, 4]

/**
 * Bonus Exercise 5: Partition
 *
 * Split array into two based on predicate.
 */
console.log('\nBonus 5: Partition');

function partition(array, predicate) {
  // TODO: Return [matching, notMatching]
}

// Test:
// const [evens, odds] = partition([1, 2, 3, 4, 5], n => n % 2 === 0);
// console.log(evens);  // [2, 4]
// console.log(odds);   // [1, 3, 5]

// =====================================================
// SOLUTIONS (Uncomment to check your answers)
// =====================================================

/*
// Exercise 1 Solution:
const squares = numbers.map(n => n * n);
const strings = numbers.map(n => String(n));

// Exercise 2 Solution:
const fullNames = users.map(u => `${u.firstName} ${u.lastName}`);
const summaries = users.map(u => ({ name: `${u.firstName} ${u.lastName}`, age: u.age }));

// Exercise 3 Solution:
const odds = nums.filter(n => n % 2 !== 0);
const large = nums.filter(n => n > 5);

// Exercise 4 Solution:
const available = products.filter(p => p.inStock);
const cheapAvailable = products.filter(p => p.price < 500 && p.inStock);

// Exercise 5 Solution:
const sum = values.reduce((acc, n) => acc + n, 0);
const avg = values.reduce((acc, n) => acc + n, 0) / values.length;

// Exercise 6 Solution:
const counts = fruits.reduce((acc, fruit) => {
    acc[fruit] = (acc[fruit] || 0) + 1;
    return acc;
}, {});

const lookup = items.reduce((acc, item) => {
    acc[item.id] = item;
    return acc;
}, {});

// Exercise 7 Solution:
const bob = employees.find(e => e.id === 102);
const engIndex = employees.findIndex(e => e.department === "Engineering");

// Exercise 8 Solution:
const hasPerfect = scores.some(s => s === 100);
const allPassing = scores.every(s => s >= 60);

// Exercise 9 Solution:
const totalCredits = transactions
    .filter(t => t.type === "credit")
    .map(t => t.amount)
    .reduce((sum, a) => sum + a, 0);

// Exercise 10 Solution:
const byAge = [...people].sort((a, b) => a.age - b.age);
const byName = [...people].sort((a, b) => a.name.localeCompare(b.name));

// Exercise 11 Solution:
function repeat(n, action) {
    for (let i = 0; i < n; i++) {
        action(i);
    }
}

// Exercise 12 Solution:
function createGreeter(greeting) {
    return function(name) {
        return `${greeting}, ${name}!`;
    };
}

// Exercise 13 Solution:
function myMap(array, transform) {
    const result = [];
    for (const item of array) {
        result.push(transform(item));
    }
    return result;
}

// Exercise 14 Solution:
function myFilter(array, predicate) {
    const result = [];
    for (const item of array) {
        if (predicate(item)) {
            result.push(item);
        }
    }
    return result;
}

// Exercise 15 Solution:
function pipe(...fns) {
    return function(value) {
        return fns.reduce((acc, fn) => fn(acc), value);
    };
}

// Bonus 1 Solution:
function groupBy(array, keyFn) {
    return array.reduce((acc, item) => {
        const key = keyFn(item);
        if (!acc[key]) acc[key] = [];
        acc[key].push(item);
        return acc;
    }, {});
}

// Bonus 2 Solution:
function compose(...fns) {
    return function(value) {
        return fns.reduceRight((acc, fn) => fn(acc), value);
    };
}

// Bonus 3 Solution:
function memoize(fn) {
    const cache = {};
    return function(...args) {
        const key = JSON.stringify(args);
        if (cache[key] === undefined) {
            cache[key] = fn(...args);
        }
        return cache[key];
    };
}

// Bonus 4 Solution:
function flatten(array, depth = 1) {
    if (depth < 1) return array.slice();
    
    return array.reduce((acc, item) => {
        if (Array.isArray(item)) {
            return acc.concat(flatten(item, depth - 1));
        }
        return acc.concat(item);
    }, []);
}

// Bonus 5 Solution:
function partition(array, predicate) {
    return array.reduce((acc, item) => {
        acc[predicate(item) ? 0 : 1].push(item);
        return acc;
    }, [[], []]);
}
*/
Exercises - JavaScript Tutorial | DeepML