Web Data Structures TypeScript Samples

Web TypeScript data structures examples including array operations, hash maps, and linked lists

Key Facts

Category
TypeScript
Items
3
Format Families
sample

Sample Overview

Web TypeScript data structures examples including array operations, hash maps, and linked lists This sample set belongs to TypeScript and can be used to test related workflows inside Elysia Tools.

💻 Array Operations typescript

🟢 simple ⭐⭐

Comprehensive array manipulation including CRUD operations, sorting, searching, filtering, and transformation

⏱️ 30 min 🏷️ typescript, web, data structures, arrays
Prerequisites: Basic TypeScript
// Web TypeScript Array Operations Examples
// Comprehensive array manipulation and processing

// 1. Basic Array Operations
class ArrayOperations<T> {
  // Create array
  static create<T>(...items: T[]): T[] {
    return [...items];
  }

  // Add element to end
  static push<T>(array: T[], item: T): number {
    return array.push(item);
  }

  // Add element to beginning
  static unshift<T>(array: T[], item: T): number {
    return array.unshift(item);
  }

  // Remove last element
  static pop<T>(array: T[]): T | undefined {
    return array.pop();
  }

  // Remove first element
  static shift<T>(array: T[]): T | undefined {
    return array.shift();
  }

  // Get element at index
  static get<T>(array: T[], index: number): T | undefined {
    return array[index];
  }

  // Set element at index
  static set<T>(array: T[], index: number, item: T): void {
    array[index] = item;
  }

  // Get array length
  static length<T>(array: T[]): number {
    return array.length;
  }

  // Check if array is empty
  static isEmpty<T>(array: T[]): boolean {
    return array.length === 0;
  }

  // Clear array
  static clear<T>(array: T[]): void {
    array.length = 0;
  }

  // Clone array
  static clone<T>(array: T[]): T[] {
    return [...array];
  }

  // Merge arrays
  static merge<T>(...arrays: T[][]): T[] {
    return arrays.flat();
  }

  // Slice array
  static slice<T>(array: T[], start: number, end?: number): T[] {
    return array.slice(start, end);
  }

  // Splice array (remove and insert)
  static splice<T>(array: T[], start: number, deleteCount: number, ...items: T[]): T[] {
    return array.splice(start, deleteCount, ...items);
  }
}

// 2. Array Searching
class ArraySearching<T> {
  // Linear search
  static linearSearch<T>(array: T[], target: T): number {
    for (let i = 0; i < array.length; i++) {
      if (array[i] === target) {
        return i;
      }
    }
    return -1;
  }

  // Binary search (requires sorted array)
  static binarySearch(array: number[], target: number): number {
    let left = 0;
    let right = array.length - 1;

    while (left <= right) {
      const mid = Math.floor((left + right) / 2);

      if (array[mid] === target) {
        return mid;
      } else if (array[mid] < target) {
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }

    return -1;
  }

  // Find element by predicate
  static find<T>(array: T[], predicate: (item: T) => boolean): T | undefined {
    return array.find(predicate);
  }

  // Find index by predicate
  static findIndex<T>(array: T[], predicate: (item: T) => boolean): number {
    return array.findIndex(predicate);
  }

  // Find all matching elements
  static findAll<T>(array: T[], predicate: (item: T) => boolean): T[] {
    return array.filter(predicate);
  }

  // Find last occurrence
  static findLast<T>(array: T[], predicate: (item: T) => boolean): T | undefined {
    for (let i = array.length - 1; i >= 0; i--) {
      if (predicate(array[i])) {
        return array[i];
      }
    }
    return undefined;
  }

  // Find last index
  static findLastIndex<T>(array: T[], predicate: (item: T) => boolean): number {
    for (let i = array.length - 1; i >= 0; i--) {
      if (predicate(array[i])) {
        return i;
      }
    }
    return -1;
  }

  // Check if element exists
  static contains<T>(array: T[], element: T): boolean {
    return array.includes(element);
  }

  // Count occurrences
  static countOccurrences<T>(array: T[], element: T): number {
    return array.filter(item => item === element).length;
  }
}

// 3. Array Sorting
class ArraySorting<T> {
  // Bubble sort
  static bubbleSort(array: number[]): number[] {
    const result = [...array];
    const n = result.length;

    for (let i = 0; i < n - 1; i++) {
      for (let j = 0; j < n - i - 1; j++) {
        if (result[j] > result[j + 1]) {
          [result[j], result[j + 1]] = [result[j + 1], result[j]];
        }
      }
    }

    return result;
  }

  // Selection sort
  static selectionSort(array: number[]): number[] {
    const result = [...array];
    const n = result.length;

    for (let i = 0; i < n - 1; i++) {
      let minIndex = i;

      for (let j = i + 1; j < n; j++) {
        if (result[j] < result[minIndex]) {
          minIndex = j;
        }
      }

      [result[i], result[minIndex]] = [result[minIndex], result[i]];
    }

    return result;
  }

  // Insertion sort
  static insertionSort(array: number[]): number[] {
    const result = [...array];

    for (let i = 1; i < result.length; i++) {
      const key = result[i];
      let j = i - 1;

      while (j >= 0 && result[j] > key) {
        result[j + 1] = result[j];
        j--;
      }

      result[j + 1] = key;
    }

    return result;
  }

  // Merge sort
  static mergeSort(array: number[]): number[] {
    if (array.length <= 1) {
      return array;
    }

    const mid = Math.floor(array.length / 2);
    const left = this.mergeSort(array.slice(0, mid));
    const right = this.mergeSort(array.slice(mid));

    return this.merge(left, right);
  }

  private static merge(left: number[], right: number[]): number[] {
    const result: number[] = [];
    let leftIndex = 0;
    let rightIndex = 0;

    while (leftIndex < left.length && rightIndex < right.length) {
      if (left[leftIndex] <= right[rightIndex]) {
        result.push(left[leftIndex++]);
      } else {
        result.push(right[rightIndex++]);
      }
    }

    return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
  }

  // Quick sort
  static quickSort(array: number[]): number[] {
    if (array.length <= 1) {
      return array;
    }

    const pivot = array[Math.floor(array.length / 2)];
    const left = array.filter(x => x < pivot);
    const middle = array.filter(x => x === pivot);
    const right = array.filter(x => x > pivot);

    return [...this.quickSort(left), ...middle, ...this.quickSort(right)];
  }

  // Sort with custom comparator
  static sortBy<T>(array: T[], comparator: (a: T, b: T) => number): T[] {
    return [...array].sort(comparator);
  }

  // Sort numbers ascending
  static sortAscending(array: number[]): number[] {
    return [...array].sort((a, b) => a - b);
  }

  // Sort numbers descending
  static sortDescending(array: number[]): number[] {
    return [...array].sort((a, b) => b - a);
  }

  // Sort by property
  static sortByProperty<T>(array: T[], property: keyof T): T[] {
    return [...array].sort((a, b) => {
      const aValue = a[property];
      const bValue = b[property];

      if (aValue < bValue) return -1;
      if (aValue > bValue) return 1;
      return 0;
    });
  }
}

// 4. Array Filtering
class ArrayFiltering<T> {
  // Filter by predicate
  static filter<T>(array: T[], predicate: (item: T) => boolean): T[] {
    return array.filter(predicate);
  }

  // Filter unique elements
  static unique<T>(array: T[]): T[] {
    return Array.from(new Set(array));
  }

  // Filter out null/undefined
  static filterNotNull<T>(array: (T | null | undefined)[]): T[] {
    return array.filter((item): item is T => item !== null && item !== undefined);
  }

  // Filter by type
  static filterByType<T, U extends T>(array: T[], typeGuard: (item: T) => item is U): U[] {
    return array.filter(typeGuard);
  }

  // Partition array
  static partition<T>(array: T[], predicate: (item: T) => boolean): [T[], T[]] {
    const truthy: T[] = [];
    const falsy: T[] = [];

    for (const item of array) {
      if (predicate(item)) {
        truthy.push(item);
      } else {
        falsy.push(item);
      }
    }

    return [truthy, falsy];
  }

  // Remove elements
  static remove<T>(array: T[], elementsToRemove: T[]): T[] {
    const removeSet = new Set(elementsToRemove);
    return array.filter(item => !removeSet.has(item));
  }

  // Remove at indices
  static removeAt<T>(array: T[], indices: number[]): T[] {
    const indexSet = new Set(indices);
    return array.filter((_, index) => !indexSet.has(index));
  }
}

// 5. Array Transformation
class ArrayTransformation<T> {
  // Map array
  static map<T, U>(array: T[], mapper: (item: T, index: number) => U): U[] {
    return array.map(mapper);
  }

  // Flat map
  static flatMap<T, U>(array: T[], mapper: (item: T) => U[]): U[] {
    return array.flatMap(mapper);
  }

  // Reduce array
  static reduce<T, U>(array: T[], reducer: (acc: U, item: T, index: number) => U, initialValue: U): U {
    return array.reduce(reducer, initialValue);
  }

  // Reverse array
  static reverse<T>(array: T[]): T[] {
    return [...array].reverse();
  }

  // Shuffle array
  static shuffle<T>(array: T[]): T[] {
    const result = [...array];

    for (let i = result.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [result[i], result[j]] = [result[j], result[i]];
    }

    return result;
  }

  // Flatten nested array
  static flatten<T>(array: T[][]): T[] {
    return array.flat();
  }

  // Group by key
  static groupBy<T>(array: T[], keyGetter: (item: T) => string): Record<string, T[]> {
    return array.reduce((groups, item) => {
      const key = keyGetter(item);
      if (!groups[key]) {
        groups[key] = [];
      }
      groups[key].push(item);
      return groups;
    }, {} as Record<string, T[]>);
  }

  // Chunk array
  static chunk<T>(array: T[], size: number): T[][] {
    const chunks: T[][] = [];

    for (let i = 0; i < array.length; i += size) {
      chunks.push(array.slice(i, i + size));
    }

    return chunks;
  }

  // Zip arrays
  static zip<T, U>(array1: T[], array2: U[]): [T, U][] {
    const length = Math.min(array1.length, array2.length);
    const result: [T, U][] = [];

    for (let i = 0; i < length; i++) {
      result.push([array1[i], array2[i]]);
    }

    return result;
  }

  // Rotate array
  static rotate<T>(array: T[], positions: number): T[] {
    if (array.length === 0) {
      return [];
    }
    const normalizedPositions = ((positions % array.length) + array.length) % array.length;
    return [
      ...array.slice(normalizedPositions),
      ...array.slice(0, normalizedPositions)
    ];
  }
}

// 6. Array Aggregation
class ArrayAggregation<T> {
  // Sum numbers
  static sum(array: number[]): number {
    return array.reduce((sum, num) => sum + num, 0);
  }

  // Average
  static average(array: number[]): number {
    if (array.length === 0) return 0;
    return this.sum(array) / array.length;
  }

  // Min value
  static min(array: number[]): number | undefined {
    if (array.length === 0) return undefined;
    return array.reduce((min, current) => current < min ? current : min, array[0]);
  }

  // Max value
  static max(array: number[]): number | undefined {
    if (array.length === 0) return undefined;
    return array.reduce((max, current) => current > max ? current : max, array[0]);
  }

  // Min and max
  static minMax(array: number[]): { min: number; max: number } | undefined {
    if (array.length === 0) return undefined;

    let min = array[0];
    let max = array[0];

    for (const num of array) {
      if (num < min) min = num;
      if (num > max) max = num;
    }

    return { min, max };
  }

  // Product
  static product(array: number[]): number {
    return array.reduce((prod, num) => prod * num, 1);
  }

  // Count by predicate
  static count<T>(array: T[], predicate: (item: T) => boolean): number {
    return array.filter(predicate).length;
  }

  // Frequency map
  static frequency<T>(array: T[]): Map<T, number> {
    const freq = new Map<T, number>();

    for (const item of array) {
      freq.set(item, (freq.get(item) || 0) + 1);
    }

    return freq;
  }

  // Most frequent
  static mostFrequent<T>(array: T[]): T | undefined {
    const freq = this.frequency(array);
    let maxCount = 0;
    let mostFrequent: T | undefined;

    for (const [item, count] of freq.entries()) {
      if (count > maxCount) {
        maxCount = count;
        mostFrequent = item;
      }
    }

    return mostFrequent;
  }
}

// 7. Array Set Operations
class ArraySetOperations<T> {
  // Union
  static union(array1: T[], array2: T[]): T[] {
    return Array.from(new Set([...array1, ...array2]));
  }

  // Intersection
  static intersection(array1: T[], array2: T[]): T[] {
    const set2 = new Set(array2);
    return array1.filter(item => set2.has(item));
  }

  // Difference
  static difference(array1: T[], array2: T[]): T[] {
    const set2 = new Set(array2);
    return array1.filter(item => !set2.has(item));
  }

  // Symmetric difference
  static symmetricDifference(array1: T[], array2: T[]): T[] {
    const set1 = new Set(array1);
    const set2 = new Set(array2);

    return [
      ...array1.filter(item => !set2.has(item)),
      ...array2.filter(item => !set1.has(item))
    ];
  }

  // Is subset
  static isSubset(array1: T[], array2: T[]): boolean {
    const set2 = new Set(array2);
    return array1.every(item => set2.has(item));
  }

  // Is superset
  static isSuperset(array1: T[], array2: T[]): boolean {
    return this.isSubset(array2, array1);
  }
}

// Usage Examples
async function demonstrateArrayOperations() {
  console.log('=== Web TypeScript Array Operations Examples ===\n');

  // 1. Basic operations
  console.log('--- 1. Basic Operations ---');
  const arr = [1, 2, 3];
  ArrayOperations.push(arr, 4);
  console.log(`After push: ${arr}`);

  ArrayOperations.unshift(arr, 0);
  console.log(`After unshift: ${arr}`);

  console.log(`Pop: ${ArrayOperations.pop(arr)}`);
  console.log(`Shift: ${ArrayOperations.shift(arr)}`);

  const merged = ArrayOperations.merge([1, 2], [3, 4], [5]);
  console.log(`Merged: ${merged}`);

  // 2. Searching
  console.log('\n--- 2. Searching ---');
  const numbers = [5, 3, 8, 1, 9, 2];
  console.log(`Array: ${numbers}`);
  console.log(`Linear search 8: index ${ArraySearching.linearSearch(numbers, 8)}`);

  const sorted = [1, 3, 5, 7, 9, 11];
  console.log(`Binary search 7: index ${ArraySearching.binarySearch(sorted, 7)}`);
  console.log(`Contains 5: ${ArraySearching.contains(numbers, 5)}`);
  console.log(`Count of 3: ${ArraySearching.countOccurrences([...numbers, 3], 3)}`);

  // 3. Sorting
  console.log('\n--- 3. Sorting ---');
  const unsorted = [64, 34, 25, 12, 22, 11, 90];
  console.log(`Original: ${unsorted}`);
  console.log(`Bubble sort: ${ArraySorting.bubbleSort(unsorted)}`);
  console.log(`Quick sort: ${ArraySorting.quickSort(unsorted)}`);
  console.log(`Ascending: ${ArraySorting.sortAscending(unsorted)}`);
  console.log(`Descending: ${ArraySorting.sortDescending(unsorted)}`);

  // 4. Filtering
  console.log('\n--- 4. Filtering ---');
  const mixed = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
  console.log(`Original: ${mixed}`);
  console.log(`Unique: ${ArrayFiltering.unique(mixed)}`);

  const [even, odd] = ArrayFiltering.partition(mixed, n => n % 2 === 0);
  console.log(`Even: ${even}`);
  console.log(`Odd: ${odd}`);

  // 5. Transformation
  console.log('\n--- 5. Transformation ---');
  const nums = [1, 2, 3, 4, 5];
  console.log(`Original: ${nums}`);
  console.log(`Doubled: ${ArrayTransformation.map(nums, n => n * 2)}`);
  console.log(`Reversed: ${ArrayTransformation.reverse(nums)}`);
  console.log(`Shuffled: ${ArrayTransformation.shuffle(nums)}`);
  console.log(`Chunked (2): ${ArrayTransformation.chunk(nums, 2).map(c => `[${c}]`).join(', ')}`);

  // 6. Aggregation
  console.log('\n--- 6. Aggregation ---');
  const values = [10, 20, 30, 40, 50];
  console.log(`Array: ${values}`);
  console.log(`Sum: ${ArrayAggregation.sum(values)}`);
  console.log(`Average: ${ArrayAggregation.average(values)}`);
  console.log(`Min: ${ArrayAggregation.min(values)}`);
  console.log(`Max: ${ArrayAggregation.max(values)}`);
  console.log(`Min/Max: ${JSON.stringify(ArrayAggregation.minMax(values))}`);

  // 7. Set operations
  console.log('\n--- 7. Set Operations ---');
  const set1 = [1, 2, 3, 4];
  const set2 = [3, 4, 5, 6];
  console.log(`Set 1: ${set1}`);
  console.log(`Set 2: ${set2}`);
  console.log(`Union: ${ArraySetOperations.union(set1, set2)}`);
  console.log(`Intersection: ${ArraySetOperations.intersection(set1, set2)}`);
  console.log(`Difference: ${ArraySetOperations.difference(set1, set2)}`);
  console.log(`Symmetric diff: ${ArraySetOperations.symmetricDifference(set1, set2)}`);

  // 8. Group by
  console.log('\n--- 8. Group By ---');
  const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 25 }
  ];

  const grouped = ArrayTransformation.groupBy(people, p => String(p.age));
  console.log('Grouped by age:', Object.entries(grouped).map(([k, v]) => `${k}: [${v.map(p => p.name).join(', ')}]`).join(', '));

  console.log('\n=== All Array Operations Examples Completed ===');
}

// Export classes
export { ArrayOperations, ArraySearching, ArraySorting, ArrayFiltering, ArrayTransformation, ArrayAggregation, ArraySetOperations };
export { demonstrateArrayOperations };

💻 Hash Map typescript

🟡 intermediate ⭐⭐⭐

Implement and use hash maps for efficient key-value storage and retrieval with collision handling

⏱️ 30 min 🏷️ typescript, web, data structures, hash map
Prerequisites: Intermediate TypeScript
// Web TypeScript Hash Map Examples
// Custom hash map implementation with collision handling

// 1. Basic Hash Map Entry
class HashMapEntry<K, V> {
  key: K;
  value: V;
  next: HashMapEntry<K, V> | null;

  constructor(key: K, value: V) {
    this.key = key;
    this.value = value;
    this.next = null;
  }
}

// 2. Hash Map Implementation
class HashMap<K, V> {
  private buckets: Array<HashMapEntry<K, V> | null>;
  private size: number;
  private capacity: number;
  private loadFactor: number;

  constructor(initialCapacity: number = 16, loadFactor: number = 0.75) {
    this.capacity = initialCapacity;
    this.loadFactor = loadFactor;
    this.size = 0;
    this.buckets = new Array(this.capacity).fill(null);
  }

  // Hash function
  private hash(key: K): number {
    const keyString = String(key);
    let hash = 0;

    for (let i = 0; i < keyString.length; i++) {
      hash = (hash << 5) - hash + keyString.charCodeAt(i);
      hash = hash | 0; // Convert to 32-bit integer
    }

    return Math.abs(hash) % this.capacity;
  }

  // Put key-value pair
  put(key: K, value: V): void {
    const index = this.hash(key);
    let entry = this.buckets[index];

    // Check if key already exists
    while (entry !== null) {
      if (entry.key === key) {
        entry.value = value;
        return;
      }
      entry = entry.next;
    }

    // Add new entry at the beginning
    const newEntry = new HashMapEntry(key, value);
    newEntry.next = this.buckets[index];
    this.buckets[index] = newEntry;
    this.size++;

    // Resize if needed
    if (this.size / this.capacity >= this.loadFactor) {
      this.resize();
    }
  }

  // Get value by key
  get(key: K): V | undefined {
    const index = this.hash(key);
    let entry = this.buckets[index];

    while (entry !== null) {
      if (entry.key === key) {
        return entry.value;
      }
      entry = entry.next;
    }

    return undefined;
  }

  // Remove key-value pair
  remove(key: K): boolean {
    const index = this.hash(key);
    let entry = this.buckets[index];
    let prev: HashMapEntry<K, V> | null = null;

    while (entry !== null) {
      if (entry.key === key) {
        if (prev === null) {
          this.buckets[index] = entry.next;
        } else {
          prev.next = entry.next;
        }
        this.size--;
        return true;
      }
      prev = entry;
      entry = entry.next;
    }

    return false;
  }

  // Check if key exists
  containsKey(key: K): boolean {
    return this.get(key) !== undefined;
  }

  // Check if value exists
  containsValue(value: V): boolean {
    for (const bucket of this.buckets) {
      let entry = bucket;
      while (entry !== null) {
        if (entry.value === value) {
          return true;
        }
        entry = entry.next;
      }
    }
    return false;
  }

  // Get all keys
  keys(): K[] {
    const keys: K[] = [];

    for (const bucket of this.buckets) {
      let entry = bucket;
      while (entry !== null) {
        keys.push(entry.key);
        entry = entry.next;
      }
    }

    return keys;
  }

  // Get all values
  values(): V[] {
    const values: V[] = [];

    for (const bucket of this.buckets) {
      let entry = bucket;
      while (entry !== null) {
        values.push(entry.value);
        entry = entry.next;
      }
    }

    return values;
  }

  // Get all entries
  entries(): Array<[K, V]> {
    const entries: Array<[K, V]> = [];

    for (const bucket of this.buckets) {
      let entry = bucket;
      while (entry !== null) {
        entries.push([entry.key, entry.value]);
        entry = entry.next;
      }
    }

    return entries;
  }

  // Get size
  getSize(): number {
    return this.size;
  }

  // Check if empty
  isEmpty(): boolean {
    return this.size === 0;
  }

  // Clear hash map
  clear(): void {
    this.buckets = new Array(this.capacity).fill(null);
    this.size = 0;
  }

  // Resize buckets
  private resize(): void {
    const oldBuckets = this.buckets;
    this.capacity *= 2;
    this.buckets = new Array(this.capacity).fill(null);
    this.size = 0;

    for (const bucket of oldBuckets) {
      let entry = bucket;
      while (entry !== null) {
        this.put(entry.key, entry.value);
        entry = entry.next;
      }
    }
  }

  // Print hash map (for debugging)
  print(): void {
    console.log('\n=== Hash Map Contents ===');
    console.log(`Size: ${this.size}, Capacity: ${this.capacity}`);

    for (let i = 0; i < this.buckets.length; i++) {
      const bucket = this.buckets[i];
      if (bucket !== null) {
        console.log(`Bucket ${i}:`);

        let entry = bucket;
        while (entry !== null) {
          console.log(`  ${entry.key} => ${entry.value}`);
          entry = entry.next;
        }
      }
    }
  }
}

// 3. Multi-Value Map (one key, multiple values)
class MultiValueMap<K, V> {
  private map = new Map<K, V[]>();

  // Add value for key
  put(key: K, value: V): void {
    if (!this.map.has(key)) {
      this.map.set(key, []);
    }
    this.map.get(key)!.push(value);
  }

  // Get all values for key
  get(key: K): V[] {
    return this.map.get(key) || [];
  }

  // Remove specific value for key
  remove(key: K, value: V): boolean {
    const values = this.map.get(key);
    if (!values) return false;

    const index = values.indexOf(value);
    if (index > -1) {
      values.splice(index, 1);

      if (values.length === 0) {
        this.map.delete(key);
      }

      return true;
    }

    return false;
  }

  // Remove all values for key
  removeAll(key: K): V[] {
    const values = this.map.get(key);
    this.map.delete(key);
    return values || [];
  }

  // Get all keys
  keys(): K[] {
    return Array.from(this.map.keys());
  }

  // Get all values
  values(): V[] {
    const allValues: V[] = [];
    for (const values of this.map.values()) {
      allValues.push(...values);
    }
    return allValues;
  }

  // Check if key exists
  containsKey(key: K): boolean {
    return this.map.has(key);
  }

  // Get size (number of keys)
  size(): number {
    return this.map.size;
  }

  // Clear map
  clear(): void {
    this.map.clear();
  }
}

// 4. LRU Cache (Least Recently Used)
class LRUCache<K, V> {
  private capacity: number;
  private cache = new Map<K, V>();

  constructor(capacity: number) {
    this.capacity = capacity;
  }

  // Get value and move to end (most recently used)
  get(key: K): V | undefined {
    if (!this.cache.has(key)) {
      return undefined;
    }

    const value = this.cache.get(key)!;
    this.cache.delete(key);
    this.cache.set(key, value);

    return value;
  }

  // Put value and evict least recently used if at capacity
  put(key: K, value: V): void {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.capacity) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }

    this.cache.set(key, value);
  }

  // Check if key exists
  has(key: K): boolean {
    return this.cache.has(key);
  }

  // Get size
  size(): number {
    return this.cache.size;
  }

  // Clear cache
  clear(): void {
    this.cache.clear();
  }

  // Get all keys (in order of least to most recently used)
  keys(): K[] {
    return Array.from(this.cache.keys());
  }
}

// 5. Hash Map Utilities
class HashMapUtilities {
  // Merge two hash maps
  static merge<K, V>(map1: Map<K, V>, map2: Map<K, V>): Map<K, V> {
    return new Map([...map1, ...map2]);
  }

  // Clone hash map
  static clone<K, V>(map: Map<K, V>): Map<K, V> {
    return new Map(map);
  }

  // Invert hash map (swap keys and values)
  static invert<K, V>(map: Map<K, V>): Map<V, K> {
    const inverted = new Map<V, K>();

    for (const [key, value] of map.entries()) {
      inverted.set(value, key);
    }

    return inverted;
  }

  // Filter hash map by predicate
  static filter<K, V>(map: Map<K, V>, predicate: (key: K, value: V) => boolean): Map<K, V> {
    const filtered = new Map<K, V>();

    for (const [key, value] of map.entries()) {
      if (predicate(key, value)) {
        filtered.set(key, value);
      }
    }

    return filtered;
  }

  // Map values
  static mapValues<K, V, U>(map: Map<K, V>, mapper: (key: K, value: V) => U): Map<K, U> {
    const result = new Map<K, U>();

    for (const [key, value] of map.entries()) {
      result.set(key, mapper(key, value));
    }

    return result;
  }

  // Group array by key function
  static groupBy<T, K>(array: T[], keyGetter: (item: T) => K): Map<K, T[]> {
    const grouped = new Map<K, T[]>();

    for (const item of array) {
      const key = keyGetter(item);

      if (!grouped.has(key)) {
        grouped.set(key, []);
      }

      grouped.get(key)!.push(item);
    }

    return grouped;
  }

  // Count occurrences
  static countOccurrences<T>(array: T[]): Map<T, number> {
    const counts = new Map<T, number>();

    for (const item of array) {
      counts.set(item, (counts.get(item) || 0) + 1);
    }

    return counts;
  }
}

// 6. Hash Map Comparison
class HashMapComparison {
  // Check if two maps are equal
  static equal<K, V>(map1: Map<K, V>, map2: Map<K, V>): boolean {
    if (map1.size !== map2.size) {
      return false;
    }

    for (const [key, value] of map1.entries()) {
      if (!map2.has(key) || map2.get(key) !== value) {
        return false;
      }
    }

    return true;
  }

  // Get keys present in map1 but not in map2
  static keyDifference<K, V>(map1: Map<K, V>, map2: Map<K, V>): Set<K> {
    const diff = new Set<K>();

    for (const key of map1.keys()) {
      if (!map2.has(key)) {
        diff.add(key);
      }
    }

    return diff;
  }

  // Get common keys
  static keyIntersection<K, V>(map1: Map<K, V>, map2: Map<K, V>): Set<K> {
    const intersection = new Set<K>();

    for (const key of map1.keys()) {
      if (map2.has(key)) {
        intersection.add(key);
      }
    }

    return intersection;
  }
}

// Usage Examples
async function demonstrateHashMap() {
  console.log('=== Web TypeScript Hash Map Examples ===\n');

  // 1. Basic hash map operations
  console.log('--- 1. Basic Hash Map ---');
  const hashMap = new HashMap<string, number>();

  hashMap.put('one', 1);
  hashMap.put('two', 2);
  hashMap.put('three', 3);

  console.log(`Get 'two': ${hashMap.get('two')}`);
  console.log(`Contains 'three': ${hashMap.containsKey('three')}`);
  console.log(`Keys: ${hashMap.keys().join(', ')}`);
  console.log(`Values: ${hashMap.values().join(', ')}`);
  console.log(`Size: ${hashMap.getSize()}`);

  hashMap.remove('two');
  console.log(`After remove 'two', size: ${hashMap.getSize()}`);

  // 2. Collision handling
  console.log('\n--- 2. Collision Handling ---');
  const smallMap = new HashMap<number, string>(4);

  // These might hash to same bucket
  smallMap.put(1, 'one');
  smallMap.put(5, 'five');
  smallMap.put(9, 'nine');

  console.log(`Get 1: ${smallMap.get(1)}`);
  console.log(`Get 5: ${smallMap.get(5)}`);
  console.log(`Get 9: ${smallMap.get(9)}`);

  smallMap.print();

  // 3. Multi-value map
  console.log('\n--- 3. Multi-Value Map ---');
  const multiMap = new MultiValueMap<string, number>();

  multiMap.put('fruits', 1);
  multiMap.put('fruits', 2);
  multiMap.put('fruits', 3);
  multiMap.put('vegetables', 10);

  console.log(`Fruits: ${multiMap.get('fruits').join(', ')}`);
  console.log(`Vegetables: ${multiMap.get('vegetables').join(', ')}`);

  multiMap.remove('fruits', 2);
  console.log(`After removing 2 from fruits: ${multiMap.get('fruits').join(', ')}`);

  // 4. LRU Cache
  console.log('\n--- 4. LRU Cache ---');
  const lru = new LRUCache<string, number>(3);

  lru.put('a', 1);
  lru.put('b', 2);
  lru.put('c', 3);
  console.log(`Cache keys: ${lru.keys().join(', ')}`);

  lru.put('d', 4); // 'a' should be evicted
  console.log(`After adding 'd': ${lru.keys().join(', ')}`);
  console.log(`Has 'a': ${lru.has('a')}`);
  console.log(`Get 'b': ${lru.get('b')}`);
  console.log(`After getting 'b': ${lru.keys().join(', ')}`);

  // 5. Hash map utilities
  console.log('\n--- 5. Hash Map Utilities ---');
  const map1 = new Map([['a', 1], ['b', 2], ['c', 3]]);
  const map2 = new Map([['c', 30], ['d', 4]]);

  const merged = HashMapUtilities.merge(map1, map2);
  console.log(`Merged: ${Array.from(merged.entries()).map(([k, v]) => `${k}:${v}`).join(', ')}`);

  const filtered = HashMapUtilities.filter(map1, (k, v) => v > 1);
  console.log(`Filtered (> 1): ${Array.from(filtered.entries()).map(([k, v]) => `${k}:${v}`).join(', ')}`);

  const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
  const counts = HashMapUtilities.countOccurrences(numbers);
  console.log(`Occurrences: ${Array.from(counts.entries()).map(([k, v]) => `${k}:${v}`).join(', ')}`);

  // 6. Group by
  console.log('\n--- 6. Group By ---');
  const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 25 },
    { name: 'David', age: 30 }
  ];

  const grouped = HashMapUtilities.groupBy(people, p => p.age);
  console.log('Grouped by age:');
  for (const [age, persons] of grouped.entries()) {
    console.log(`  ${age}: ${persons.map(p => p.name).join(', ')}`);
  }

  // 7. Hash map comparison
  console.log('\n--- 7. Hash Map Comparison ---');
  const mapA = new Map([['x', 1], ['y', 2]]);
  const mapB = new Map([['x', 1], ['y', 2]]);
  const mapC = new Map([['x', 1], ['z', 2]]);

  console.log(`A equals B: ${HashMapComparison.equal(mapA, mapB)}`);
  console.log(`A equals C: ${HashMapComparison.equal(mapA, mapC)}`);

  const diff = HashMapComparison.keyDifference(mapA, mapC);
  console.log(`A - C keys: ${Array.from(diff).join(', ')}`);

  const intersection = HashMapComparison.keyIntersection(mapA, mapC);
  console.log(`A ∩ C keys: ${Array.from(intersection).join(', ')}`);

  console.log('\n=== All Hash Map Examples Completed ===');
}

// Export classes
export { HashMap, HashMapEntry, MultiValueMap, LRUCache, HashMapUtilities, HashMapComparison };
export { demonstrateHashMap };

💻 Linked List typescript

🟡 intermediate ⭐⭐⭐

Create and manipulate singly and doubly linked lists with traversal and modification operations

⏱️ 30 min 🏷️ typescript, web, data structures, linked list
Prerequisites: Intermediate TypeScript, Pointers and References
// Web TypeScript Linked List Examples
// Singly and doubly linked list implementations

// 1. Singly Linked List Node
class ListNode<T> {
  value: T;
  next: ListNode<T> | null;

  constructor(value: T) {
    this.value = value;
    this.next = null;
  }
}

// 2. Singly Linked List
class LinkedList<T> {
  private head: ListNode<T> | null = null;
  private tail: ListNode<T> | null = null;
  private length: number = 0;

  // Add to end
  append(value: T): void {
    const newNode = new ListNode(value);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail!.next = newNode;
      this.tail = newNode;
    }

    this.length++;
  }

  // Add to beginning
  prepend(value: T): void {
    const newNode = new ListNode(value);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.next = this.head;
      this.head = newNode;
    }

    this.length++;
  }

  // Insert at index
  insert(index: number, value: T): boolean {
    if (index < 0 || index > this.length) {
      return false;
    }

    if (index === 0) {
      this.prepend(value);
      return true;
    }

    if (index === this.length) {
      this.append(value);
      return true;
    }

    const newNode = new ListNode(value);
    const current = this.getNodeAt(index - 1);

    if (current) {
      newNode.next = current.next;
      current.next = newNode;
      this.length++;
      return true;
    }

    return false;
  }

  // Remove at index
  removeAt(index: number): T | null {
    if (index < 0 || index >= this.length) {
      return null;
    }

    if (index === 0) {
      const value = this.head!.value;
      this.head = this.head!.next;

      if (!this.head) {
        this.tail = null;
      }

      this.length--;
      return value;
    }

    const prev = this.getNodeAt(index - 1);
    if (prev && prev.next) {
      const value = prev.next.value;
      prev.next = prev.next.next;

      if (!prev.next) {
        this.tail = prev;
      }

      this.length--;
      return value;
    }

    return null;
  }

  // Remove first occurrence of value
  remove(value: T): boolean {
    if (!this.head) {
      return false;
    }

    if (this.head.value === value) {
      this.head = this.head.next;

      if (!this.head) {
        this.tail = null;
      }

      this.length--;
      return true;
    }

    let current = this.head;
    while (current.next) {
      if (current.next.value === value) {
        current.next = current.next.next;

        if (!current.next) {
          this.tail = current;
        }

        this.length--;
        return true;
      }
      current = current.next;
    }

    return false;
  }

  // Get value at index
  get(index: number): T | null {
    if (index < 0 || index >= this.length) {
      return null;
    }

    const node = this.getNodeAt(index);
    return node ? node.value : null;
  }

  // Find index of value
  indexOf(value: T): number {
    let current = this.head;
    let index = 0;

    while (current) {
      if (current.value === value) {
        return index;
      }
      current = current.next;
      index++;
    }

    return -1;
  }

  // Check if contains value
  contains(value: T): boolean {
    return this.indexOf(value) !== -1;
  }

  // Get size
  size(): number {
    return this.length;
  }

  // Check if empty
  isEmpty(): boolean {
    return this.length === 0;
  }

  // Clear list
  clear(): void {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  // Convert to array
  toArray(): T[] {
    const result: T[] = [];
    let current = this.head;

    while (current) {
      result.push(current.value);
      current = current.next;
    }

    return result;
  }

  // Reverse list
  reverse(): void {
    let prev: ListNode<T> | null = null;
    let current = this.head;
    this.tail = this.head;

    while (current) {
      const next = current.next;
      current.next = prev;
      prev = current;
      current = next;
    }

    this.head = prev;
  }

  // Get node at index (private helper)
  private getNodeAt(index: number): ListNode<T> | null {
    let current = this.head;
    let count = 0;

    while (current && count < index) {
      current = current.next;
      count++;
    }

    return current;
  }

  // Print list
  print(): void {
    const values = this.toArray();
    console.log(`[${values.join(' -> ')}]`);
  }
}

// 3. Doubly Linked List Node
class DoublyListNode<T> {
  value: T;
  next: DoublyListNode<T> | null;
  prev: DoublyListNode<T> | null;

  constructor(value: T) {
    this.value = value;
    this.next = null;
    this.prev = null;
  }
}

// 4. Doubly Linked List
class DoublyLinkedList<T> {
  private head: DoublyListNode<T> | null = null;
  private tail: DoublyListNode<T> | null = null;
  private length: number = 0;

  // Add to end
  append(value: T): void {
    const newNode = new DoublyListNode(value);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.prev = this.tail;
      this.tail!.next = newNode;
      this.tail = newNode;
    }

    this.length++;
  }

  // Add to beginning
  prepend(value: T): void {
    const newNode = new DoublyListNode(value);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.next = this.head;
      this.head.prev = newNode;
      this.head = newNode;
    }

    this.length++;
  }

  // Insert at index
  insert(index: number, value: T): boolean {
    if (index < 0 || index > this.length) {
      return false;
    }

    if (index === 0) {
      this.prepend(value);
      return true;
    }

    if (index === this.length) {
      this.append(value);
      return true;
    }

    const newNode = new DoublyListNode(value);
    const current = this.getNodeAt(index);

    if (current) {
      newNode.prev = current.prev;
      newNode.next = current;
      current.prev!.next = newNode;
      current.prev = newNode;
      this.length++;
      return true;
    }

    return false;
  }

  // Remove at index
  removeAt(index: number): T | null {
    if (index < 0 || index >= this.length) {
      return null;
    }

    const node = this.getNodeAt(index);
    if (!node) {
      return null;
    }

    if (node.prev) {
      node.prev.next = node.next;
    } else {
      this.head = node.next;
    }

    if (node.next) {
      node.next.prev = node.prev;
    } else {
      this.tail = node.prev;
    }

    this.length--;
    return node.value;
  }

  // Get value at index
  get(index: number): T | null {
    if (index < 0 || index >= this.length) {
      return null;
    }

    const node = this.getNodeAt(index);
    return node ? node.value : null;
  }

  // Find index of value
  indexOf(value: T): number {
    let current = this.head;
    let index = 0;

    while (current) {
      if (current.value === value) {
        return index;
      }
      current = current.next;
      index++;
    }

    return -1;
  }

  // Get size
  size(): number {
    return this.length;
  }

  // Check if empty
  isEmpty(): boolean {
    return this.length === 0;
  }

  // Clear list
  clear(): void {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  // Convert to array
  toArray(): T[] {
    const result: T[] = [];
    let current = this.head;

    while (current) {
      result.push(current.value);
      current = current.next;
    }

    return result;
  }

  // Convert to reversed array
  toArrayReverse(): T[] {
    const result: T[] = [];
    let current = this.tail;

    while (current) {
      result.push(current.value);
      current = current.prev;
    }

    return result;
  }

  // Get node at index (private helper)
  private getNodeAt(index: number): DoublyListNode<T> | null {
    // Optimize by starting from closest end
    if (index < this.length / 2) {
      let current = this.head;
      let count = 0;

      while (current && count < index) {
        current = current.next;
        count++;
      }

      return current;
    } else {
      let current = this.tail;
      let count = this.length - 1;

      while (current && count > index) {
        current = current.prev;
        count--;
      }

      return current;
    }
  }

  // Print list forward
  printForward(): void {
    const values = this.toArray();
    console.log(`Forward: [${values.join(' <-> ')}]`);
  }

  // Print list backward
  printBackward(): void {
    const values = this.toArrayReverse();
    console.log(`Backward: [${values.join(' <-> ')}]`);
  }
}

// 5. Linked List Utilities
class LinkedListUtilities {
  // Detect cycle in linked list
  static hasCycle<T>(head: ListNode<T> | null): boolean {
    if (!head) {
      return false;
    }

    let slow = head;
    let fast = head;

    while (fast && fast.next) {
      slow = slow.next!;
      fast = fast.next.next;

      if (slow === fast) {
        return true;
      }
    }

    return false;
  }

  // Find middle node
  static findMiddle<T>(head: ListNode<T> | null): ListNode<T> | null {
    if (!head) {
      return null;
    }

    let slow = head;
    let fast = head;

    while (fast && fast.next) {
      slow = slow.next!;
      fast = fast.next.next;
    }

    return slow;
  }

  // Reverse linked list
  static reverse<T>(head: ListNode<T> | null): ListNode<T> | null {
    let prev: ListNode<T> | null = null;
    let current = head;

    while (current) {
      const next = current.next;
      current.next = prev;
      prev = current;
      current = next;
    }

    return prev;
  }

  // Merge two sorted lists
  static mergeSortedLists<T>(
    list1: ListNode<T> | null,
    list2: ListNode<T> | null,
    compare: (a: T, b: T) => number
  ): ListNode<T> | null {
    const dummy = new ListNode<T>(null as T);
    let current = dummy;

    while (list1 && list2) {
      if (compare(list1.value, list2.value) <= 0) {
        current.next = list1;
        list1 = list1.next;
      } else {
        current.next = list2;
        list2 = list2.next;
      }
      current = current.next;
    }

    current.next = list1 || list2;
    return dummy.next;
  }

  // Create linked list from array
  static fromArray<T>(values: T[]): LinkedList<T> {
    const list = new LinkedList<T>();
    for (const value of values) {
      list.append(value);
    }
    return list;
  }
}

// 6. Linked List Algorithms
class LinkedListAlgorithms {
  // Check if palindrome
  static isPalindrome<T>(list: LinkedList<T>): boolean {
    const values = list.toArray();
    const reversed = [...values].reverse();

    return JSON.stringify(values) === JSON.stringify(reversed);
  }

  // Remove nth node from end
  static removeNthFromEnd<T>(list: LinkedList<T>, n: number): boolean {
    const index = list.size() - n;

    if (index < 0) {
      return false;
    }

    return list.removeAt(index) !== null;
  }

  // Swap nodes in pairs
  static swapPairs<T>(list: LinkedList<T>): void {
    for (let i = 0; i < list.size() - 1; i += 2) {
      const first = list.get(i);
      const second = list.get(i + 1);

      if (first !== null && second !== null) {
        list.removeAt(i);
        list.removeAt(i);
        list.insert(i, second);
        list.insert(i + 1, first);
      }
    }
  }

  // Rotate list to the right by k places
  static rotateRight<T>(list: LinkedList<T>, k: number): void {
    if (list.isEmpty() || k === 0) {
      return;
    }

    const size = list.size();
    k = k % size;

    if (k === 0) {
      return;
    }

    // Get the split point
    const splitIndex = size - k;

    // Create new list with rotated elements
    const values = list.toArray();
    const rotated = [
      ...values.slice(splitIndex),
      ...values.slice(0, splitIndex)
    ];

    list.clear();
    for (const value of rotated) {
      list.append(value);
    }
  }
}

// Usage Examples
async function demonstrateLinkedList() {
  console.log('=== Web TypeScript Linked List Examples ===\n');

  // 1. Singly linked list basics
  console.log('--- 1. Singly Linked List ---');
  const list = new LinkedList<number>();

  list.append(1);
  list.append(2);
  list.append(3);
  list.prepend(0);

  console.log('After adding elements:');
  list.print();

  console.log(`Get index 2: ${list.get(2)}`);
  console.log(`Index of 2: ${list.indexOf(2)}`);
  console.log(`Contains 3: ${list.contains(3)}`);
  console.log(`Size: ${list.size()}`);

  list.insert(2, 100);
  console.log('After inserting 100 at index 2:');
  list.print();

  list.removeAt(2);
  console.log('After removing index 2:');
  list.print();

  list.reverse();
  console.log('After reversing:');
  list.print();

  // 2. Doubly linked list
  console.log('\n--- 2. Doubly Linked List ---');
  const doublyList = new DoublyLinkedList<string>();

  doublyList.append('first');
  doublyList.append('second');
  doublyList.append('third');
  doublyList.prepend('zero');

  console.log('Forward:');
  doublyList.printForward();

  console.log('Backward:');
  doublyList.printBackward();

  doublyList.insert(2, 'middle');
  console.log('After inserting at index 2:');
  doublyList.printForward();

  console.log(`Removed at index 2: ${doublyList.removeAt(2)}`);
  doublyList.printForward();

  // 3. Linked list utilities
  console.log('\n--- 3. Linked List Utilities ---');

  // Create a list for utilities
  const utilList = LinkedListUtilities.fromArray([1, 2, 3, 4, 5]);
  console.log('Created from array [1,2,3,4,5]:');
  utilList.print();

  // Find middle
  const middle = LinkedListUtilities.findMiddle(utilList['head'] || null);
  console.log(`Middle node value: ${middle?.value}`);

  // Reverse
  const reversed = LinkedListUtilities.reverse(utilList['head'] || null);
  console.log('Reversed:');
  let current = reversed;
  while (current) {
    console.log(current.value + ' -> ');
    current = current.next;
  }

  // 4. Linked list algorithms
  console.log('\n--- 4. Linked List Algorithms ---');

  // Palindrome check
  const palindromeList = LinkedListUtilities.fromArray([1, 2, 3, 2, 1]);
  console.log(`Is [1,2,3,2,1] palindrome: ${LinkedListAlgorithms.isPalindrome(palindromeList)}`);

  const nonPalindromeList = LinkedListUtilities.fromArray([1, 2, 3, 4, 5]);
  console.log(`Is [1,2,3,4,5] palindrome: ${LinkedListAlgorithms.isPalindrome(nonPalindromeList)}`);

  // Remove nth from end
  const removeList = LinkedListUtilities.fromArray([1, 2, 3, 4, 5]);
  console.log('Before removing 2nd from end:');
  removeList.print();
  LinkedListAlgorithms.removeNthFromEnd(removeList, 2);
  console.log('After removing 2nd from end:');
  removeList.print();

  // Rotate right
  const rotateList = LinkedListUtilities.fromArray([1, 2, 3, 4, 5]);
  console.log('Before rotating right by 2:');
  rotateList.print();
  LinkedListAlgorithms.rotateRight(rotateList, 2);
  console.log('After rotating right by 2:');
  rotateList.print();

  // Swap pairs
  const swapList = LinkedListUtilities.fromArray([1, 2, 3, 4, 5]);
  console.log('Before swapping pairs:');
  swapList.print();
  LinkedListAlgorithms.swapPairs(swapList);
  console.log('After swapping pairs:');
  swapList.print();

  // 5. Conversion
  console.log('\n--- 5. Conversion ---');
  const arr = [10, 20, 30, 40, 50];
  const listFromArray = LinkedListUtilities.fromArray(arr);
  console.log(`Array: [${arr.join(', ')}]`);
  console.log('Linked list:');
  listFromArray.print();

  const backToArray = listFromArray.toArray();
  console.log(`Back to array: [${backToArray.join(', ')}]`);

  console.log('\n=== All Linked List Examples Completed ===');
}

// Export classes
export { ListNode, LinkedList, DoublyListNode, DoublyLinkedList, LinkedListUtilities, LinkedListAlgorithms };
export { demonstrateLinkedList };