1+ /**
2+ * Utility class designed to provide O(1) lookups for arrays of objects.
3+ * It uses a WeakMap to cache the positions of elements based on a specific property.
4+ * The WeakMap ensures that once the array is garbage collected, its associated cache is also cleared, preventing memory leaks.
5+ */
6+ export class ArrayIndexer {
7+ /**
8+ * The cache stores the array instance as the WeakMap key.
9+ * The value is an internal Map where:
10+ * - Key: The name of the property used for indexing (e.g., 'identifier').
11+ * - Value: A Record mapping the actual property values to their index in the array.
12+ */
13+ private static readonly cache = new WeakMap < any [ ] , Map < string , Record < string , number > > > ( ) ;
14+
15+ /**
16+ * Retrieves or builds a dictionary (Record) of array indices based on a specified property.
17+ * * @param array The array instance to be indexed.
18+ * @param propertyNameForKey The property key of the objects inside the array used to build the index.
19+ * @returns A Record mapping the property values to their corresponding indices in the array.
20+ */
21+ static getOrSetPositions < T > ( array : T [ ] , propertyNameForKey : keyof T ) : Record < string , number > {
22+ const propertyString = String ( propertyNameForKey ) ;
23+
24+ // 1. Check if we already have cache entries for this specific array instance
25+ let arrayRecords = this . cache . get ( array ) ;
26+
27+ if ( arrayRecords ) {
28+ // 2. Check if we already computed the index Record for this specific property
29+ const cachedRecord = arrayRecords . get ( propertyString ) ;
30+ if ( cachedRecord ) {
31+ return cachedRecord ; // Cache HIT: Return the existing index map
32+ }
33+ } else {
34+ // Initialize the internal Map for this new array instance
35+ arrayRecords = new Map < string , Record < string , number > > ( ) ;
36+ this . cache . set ( array , arrayRecords ) ;
37+ }
38+
39+ // 3. Cache MISS: Build the index Record by iterating through the array O(N)
40+ const record : Record < string , number > = { } ;
41+
42+ for ( let index = 0 ; index < array . length ; index ++ ) {
43+ const element = array [ index ] ;
44+ const key = String ( element [ propertyNameForKey ] ) ;
45+
46+ // Map the property's stringified value to its position (index) in the array
47+ record [ key ] = index ;
48+ }
49+
50+ // 4. Save the newly built Record into the cache map for future use
51+ arrayRecords . set ( propertyString , record ) ;
52+
53+ return record ;
54+ }
55+
56+ /**
57+ * Quickly retrieves an item from the array using the specified property and its value.
58+ * Leverages the cached index Record to perform an O(1) lookup.
59+ * * @param array The array to search in.
60+ * @param propertyNameForKey The property used for matching.
61+ * @param searchedKeyValue The exact value of the property to find.
62+ * @returns The found element, or undefined if it doesn't exist.
63+ */
64+ static getItemByKeyValue < T > ( array : T [ ] , propertyNameForKey : keyof T , searchedKeyValue : string | number ) : T | undefined {
65+ // Retrieve the cached index mapping for this array and property
66+ const index = this . getOrSetPositions ( array , propertyNameForKey ) [ String ( searchedKeyValue ) ] ;
67+
68+ // If the index doesn't exist in our map, the item is not in the array
69+ if ( index === undefined ) {
70+ return undefined ;
71+ }
72+
73+ // Return the element directly from the array using the fast O(1) index lookup
74+ return array [ index ] ;
75+ }
76+ }
0 commit comments