javascript

exercises

exercises.js
/**
 * 6.3 Maps and Sets - Exercises
 * Practice with ES6 Collection Data Structures
 */

// ============================================
// EXERCISE 1: Basic Map Operations
// ============================================
/**
 * Create a Map to store student grades
 * - Add 5 students with their grades
 * - Calculate the average grade
 * - Find the student with highest grade
 * - Return an object with: average, highest: {name, grade}
 */
function studentGrades() {
  // Your code here
}

// console.log(studentGrades());
// Expected: { average: XX, highest: { name: 'StudentName', grade: XX } }

// ============================================
// EXERCISE 2: Object to Map Conversion
// ============================================
/**
 * Convert a nested object to a Map where:
 * - Keys are dot-notation paths
 * - Values are the leaf values
 *
 * Example: { a: { b: 1, c: 2 } } => Map { 'a.b' => 1, 'a.c' => 2 }
 */
function flattenToMap(obj, prefix = '') {
  // Your code here
}

// const nested = { user: { name: 'Alice', address: { city: 'NYC', zip: '10001' } } };
// console.log([...flattenToMap(nested)]);
// Expected: [['user.name', 'Alice'], ['user.address.city', 'NYC'], ['user.address.zip', '10001']]

// ============================================
// EXERCISE 3: Remove Duplicates Preserving Order
// ============================================
/**
 * Remove duplicate objects from array based on a key
 * Preserve the first occurrence
 */
function removeDuplicatesByKey(arr, key) {
  // Your code here
}

// const users = [
//     { id: 1, name: 'Alice' },
//     { id: 2, name: 'Bob' },
//     { id: 1, name: 'Alice Updated' },
//     { id: 3, name: 'Charlie' }
// ];
// console.log(removeDuplicatesByKey(users, 'id'));
// Expected: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]

// ============================================
// EXERCISE 4: Set Operations Class
// ============================================
/**
 * Create a SuperSet class that extends Set with:
 * - union(otherSet): returns new SuperSet with all elements
 * - intersection(otherSet): returns new SuperSet with common elements
 * - difference(otherSet): returns new SuperSet with elements not in otherSet
 * - isSubsetOf(otherSet): returns boolean
 * - isSupersetOf(otherSet): returns boolean
 */
class SuperSet extends Set {
  // Your code here
}

// const a = new SuperSet([1, 2, 3, 4]);
// const b = new SuperSet([3, 4, 5, 6]);
// console.log([...a.union(b)]);        // [1, 2, 3, 4, 5, 6]
// console.log([...a.intersection(b)]); // [3, 4]
// console.log([...a.difference(b)]);   // [1, 2]

// ============================================
// EXERCISE 5: LRU Cache with Map
// ============================================
/**
 * Implement an LRU (Least Recently Used) Cache using Map
 * - constructor(capacity): max items to store
 * - get(key): return value or -1, marks as recently used
 * - put(key, value): add/update value, evict LRU if at capacity
 *
 * Hint: Map maintains insertion order, use delete+set to move to end
 */
class LRUCache {
  // Your code here
}

// const cache = new LRUCache(3);
// cache.put('a', 1);
// cache.put('b', 2);
// cache.put('c', 3);
// console.log(cache.get('a'));  // 1 (moves 'a' to recently used)
// cache.put('d', 4);            // Evicts 'b' (least recently used)
// console.log(cache.get('b'));  // -1 (was evicted)

// ============================================
// EXERCISE 6: Word Frequency Counter
// ============================================
/**
 * Count word frequency in a text, returning a Map
 * - Ignore case
 * - Ignore punctuation
 * - Return sorted by frequency (descending)
 */
function wordFrequency(text) {
  // Your code here
}

// const text = "The quick brown fox jumps over the lazy dog. The dog was not amused.";
// console.log([...wordFrequency(text)]);
// Expected: [['the', 3], ['dog', 2], ...]

// ============================================
// EXERCISE 7: Two Sum with Map
// ============================================
/**
 * Given an array of numbers and a target sum,
 * return indices of two numbers that add up to target
 * Use Map for O(n) solution
 */
function twoSum(nums, target) {
  // Your code here
}

// console.log(twoSum([2, 7, 11, 15], 9));  // [0, 1]
// console.log(twoSum([3, 2, 4], 6));       // [1, 2]

// ============================================
// EXERCISE 8: Group Anagrams with Map
// ============================================
/**
 * Group words that are anagrams of each other
 * Return a Map where key is sorted letters, value is array of words
 */
function groupAnagrams(words) {
  // Your code here
}

// console.log(groupAnagrams(['eat', 'tea', 'tan', 'ate', 'nat', 'bat']));
// Expected Map: { 'aet' => ['eat', 'tea', 'ate'], 'ant' => ['tan', 'nat'], 'abt' => ['bat'] }

// ============================================
// EXERCISE 9: WeakMap for Private Properties
// ============================================
/**
 * Create a Password class that stores passwords securely using WeakMap
 * - setPassword(password): hash and store password
 * - checkPassword(password): verify password
 * - changePassword(oldPass, newPass): change if old is correct
 *
 * Simple hash: password.split('').reduce((a, c) => a + c.charCodeAt(0), 0)
 */
const _passwords = new WeakMap();

class Password {
  // Your code here
}

// const pwd = new Password();
// pwd.setPassword('secret123');
// console.log(pwd.checkPassword('secret123'));  // true
// console.log(pwd.checkPassword('wrong'));      // false
// console.log(pwd.password);                    // undefined

// ============================================
// EXERCISE 10: Find First Unique Character
// ============================================
/**
 * Find the first non-repeating character in a string
 * Return its index, or -1 if none exists
 * Use Map to count occurrences
 */
function firstUniqChar(s) {
  // Your code here
}

// console.log(firstUniqChar('leetcode'));     // 0 ('l')
// console.log(firstUniqChar('loveleetcode')); // 2 ('v')
// console.log(firstUniqChar('aabb'));         // -1

// ============================================
// EXERCISE 11: Intersection of Multiple Arrays
// ============================================
/**
 * Find elements that appear in ALL arrays
 * Use Set operations
 */
function intersectionAll(...arrays) {
  // Your code here
}

// console.log(intersectionAll([1, 2, 3], [2, 3, 4], [3, 4, 5]));  // [3]
// console.log(intersectionAll([1, 2], [2, 3], [2, 4]));          // [2]

// ============================================
// EXERCISE 12: Event Emitter with Map
// ============================================
/**
 * Create an EventEmitter class using Map:
 * - on(event, callback): register listener
 * - off(event, callback): remove listener
 * - emit(event, ...args): call all listeners with args
 * - once(event, callback): listener that fires only once
 */
class EventEmitter {
  // Your code here
}

// const emitter = new EventEmitter();
// const handler = (data) => console.log('Received:', data);
// emitter.on('message', handler);
// emitter.emit('message', 'Hello!');  // Logs: Received: Hello!
// emitter.off('message', handler);
// emitter.emit('message', 'Hello again!');  // Nothing

// ============================================
// BONUS: Implement a Trie with Map
// ============================================
/**
 * Implement a Trie (prefix tree) using Maps
 * - insert(word): add a word
 * - search(word): check if word exists
 * - startsWith(prefix): check if any word starts with prefix
 * - getWordsWithPrefix(prefix): return all words with prefix
 */
class Trie {
  // Your code here
}

// const trie = new Trie();
// trie.insert('apple');
// trie.insert('app');
// trie.insert('application');
// console.log(trie.search('app'));        // true
// console.log(trie.search('ap'));         // false
// console.log(trie.startsWith('app'));    // true
// console.log(trie.getWordsWithPrefix('app')); // ['app', 'apple', 'application']

// ============================================
// SOLUTIONS (uncomment to check)
// ============================================

/*
// Solution 1
function studentGrades() {
    const grades = new Map([
        ['Alice', 95],
        ['Bob', 87],
        ['Charlie', 92],
        ['Diana', 78],
        ['Eve', 88]
    ]);
    
    let sum = 0;
    let highest = { name: '', grade: -Infinity };
    
    for (const [name, grade] of grades) {
        sum += grade;
        if (grade > highest.grade) {
            highest = { name, grade };
        }
    }
    
    return {
        average: sum / grades.size,
        highest
    };
}

// Solution 5
class LRUCache {
    constructor(capacity) {
        this.capacity = capacity;
        this.cache = new Map();
    }
    
    get(key) {
        if (!this.cache.has(key)) return -1;
        const value = this.cache.get(key);
        // Move to end (most recently used)
        this.cache.delete(key);
        this.cache.set(key, value);
        return value;
    }
    
    put(key, value) {
        if (this.cache.has(key)) {
            this.cache.delete(key);
        } else if (this.cache.size >= this.capacity) {
            // Delete first (least recently used)
            const firstKey = this.cache.keys().next().value;
            this.cache.delete(firstKey);
        }
        this.cache.set(key, value);
    }
}

// Solution 7
function twoSum(nums, target) {
    const seen = new Map();
    for (let i = 0; i < nums.length; i++) {
        const complement = target - nums[i];
        if (seen.has(complement)) {
            return [seen.get(complement), i];
        }
        seen.set(nums[i], i);
    }
    return [];
}
*/
Exercises - JavaScript Tutorial | DeepML