@solancer/two-way-map
v1.0.4
Published
A TypeScript library providing two-way mapping functionality with order preservation. It is ideal for scenarios requiring bidirectional lookups while maintaining the insertion order of elements.
Downloads
20
Maintainers
Readme
Two-Way Map
A TypeScript library providing two-way mapping functionality with order preservation. It is ideal for scenarios requiring bidirectional lookups while maintaining the insertion order of elements. This class offers an intuitive API that aligns with common data structure operations, making it suitable for a variety of use cases.
Features
- Two-way Mapping: Enables association of keys with values and vice versa, allowing for efficient bidirectional lookups.
- Order Preservation: Keeps track of the insertion order of elements, ensuring predictable iteration and retrieval.
- Extendable: Designed to be easily extendable for various data types, catering to diverse application needs.
- TypeScript Support: Full TypeScript support ensures type safety and provides IntelliSense for an enhanced development experience in IDEs.
Use Cases
Two-Way Map
is versatile and can be utilized in various real-world scenarios, both in frontend and backend development.
Frontend Use Cases
UI Component State and Data Mapping: Manage state and data of interactive components like graphs or tables efficiently by mapping component IDs to their states or data objects, facilitating quick state lookups and rendering logic.
Caching User Inputs: In complex forms or multi-step inputs, use
Two-Way Map
to cache user inputs, aiding in validation, auto-fill features, and quick access to input values.Routing and Navigation: In Single Page Applications (SPAs), map route paths to corresponding view components or page titles for efficient routing and dynamic updates of browser titles or breadcrumbs.
Internationalization and Localization: Simplify the process of handling multiple languages by mapping translation keys to actual text, making it easier to update text or locate the key associated with specific translated content.
Backend Use Cases
Database ID and Object Mapping: Efficiently map database IDs to their corresponding record objects and vice versa, enabling quick retrieval and management of database records.
Session and User Management: Utilize
Two-Way Map
for mapping session IDs to user objects or user-specific data, streamlining session management and user data retrieval.Reverse Lookup in APIs: Optimize the lookup and validation process in APIs that support querying by different fields, such as username, email, or user ID, by using
Two-Way Map
for quick field-value mapping.Data Synchronization: In microservices architecture or distributed systems, keep track of data entities and their corresponding states across different services, aiding in data synchronization and consistency.
These use cases demonstrate the Two-Way Map
's ability to enhance efficiency and simplify complex data handling tasks in both frontend and backend environments.
Installation
To install two-way-map
, use the following command:
npm install @solancer/two-way-map
Usage
Setting and Getting Values
import { TwoWayMap } from "@solancer/two-way-map";
const map = new TwoWayMap<string, number>();
// Adding key-value pairs
map.set("apple", 1);
map.set("banana", 2);
map.set("cherry", 3);
// Retrieving values
console.log(map.get("banana")); // Outputs: 2
console.log(map.getByValue(3)); // Outputs: 'cherry'
Deleting Elements
// Deleting an element
map.delete("banana");
// Trying to get deleted element
console.log(map.get("banana")); // Outputs: undefined
Iterating Over Elements
// Iterating over keys
for (const key of map.keys()) {
console.log(key);
}
// Iterating over values
for (const value of map.values()) {
console.log(value);
}
Using pop and popitem
// Popping a value by key
console.log(map.pop("apple")); // Outputs: 1
// Popping the last item
console.log(map.popitem()); // Outputs: ['cherry', 3]
Copying and Clearing the Map
// Creating a copy of the map
const copyMap = map.copy();
// Clearing all items from the map
map.clear();
console.log(map.keys()); // Outputs: []
Advanced Usage Example
Let's combine several operations to demonstrate a more complex scenario:
const fruitMap = new TwoWayMap<string, number>();
// Adding fruits
fruitMap.set("apple", 1);
fruitMap.set("banana", 2);
fruitMap.set("cherry", 3);
// Displaying all fruits
console.log("Fruits in the map:", fruitMap.keys()); // Outputs: ['apple', 'banana', 'cherry']
// Checking a specific fruit
console.log("Banana's number:", fruitMap.get("banana")); // Outputs: 2
// Removing a fruit
fruitMap.delete("apple");
console.log("Fruits after deleting apple:", fruitMap.keys()); // Outputs: ['banana', 'cherry']
// Popping the last item
const lastFruit = fruitMap.popitem();
console.log("Popped the last fruit:", lastFruit); // Outputs: ['cherry', 3]
// Remaining fruits
console.log("Remaining fruits:", fruitMap.entries()); // Outputs: [['banana', 2]]
// Copying and clearing
const fruitMapCopy = fruitMap.copy();
fruitMap.clear();
console.log("Original map after clearing:", fruitMap.keys()); // Outputs: []
console.log("Copied map:", fruitMapCopy.entries()); // Outputs: [['banana', 2]]
TwoWayMap API Reference
Class: TwoWayMap<K, V>
A two-way map that allows for key-to-value and value-to-key mappings, preserving the order in which items are added.
Constructor
constructor()
: Initializes a new instance of theTwoWayMap
class.
Methods
set
set(key: K, value: V): void
Adds or updates a key-value pair in the map.
Parameters:
key: K
- The key to set.value: V
- The value to be associated with the key.
get
get(key: K): V | undefined
Retrieves the value associated with a given key.
Parameters:
key: K
- The key whose value is to be retrieved.
Returns: The value associated with the key, or
undefined
if the key does not exist.
getByValue
getByValue(value: V): K | undefined
Retrieves the key associated with a given value.
Parameters:
value: V
- The value whose key is to be retrieved.
Returns: The key associated with the value, or
undefined
if the value does not exist.
delete
delete(key: K): boolean
Removes a key-value pair from the map.
Parameters:
key: K
- The key to remove.
Returns:
true
if the key was found and removed,false
otherwise.
keys
keys(): K[]
Returns an array of keys in the map, in the order they were added.
Returns: An array of keys.
values
values(): V[]
Returns an array of values in the map, in the order their corresponding keys were added.
Returns: An array of values.
entries
entries(): [K, V][]
Returns an array of [key, value] pairs in the map, in the order they were added.
Returns: An array of [key, value] pairs.
pop
pop(key: K, defaultValue?: V): V | undefined
Removes the value for the given key and returns it, or returns the
defaultValue
if the key is not in the map.Parameters:
key: K
- The key to pop.defaultValue: V
(optional) - The value to return if the key is not found.
Returns: The value associated with the key, or
defaultValue
if provided, orundefined
.
popitem
popitem(last: boolean = true): [K, V] | undefined
Removes and returns the last (or first, if
last
isfalse
) key-value pair from the map.Parameters:
last: boolean
(optional) - Specifies whether to pop the last item (true
) or the first item (false
).
Returns: The last or first [key, value] pair if the map is not empty, or
undefined
if it is.
copy
copy(): TwoWayMap<K, V>
Creates and returns a shallow copy of the map.
Returns: A new
TwoWayMap
instance that contains the same key-value pairs.
clear
clear(): void
Removes all key-value pairs from the map.
Data Structure and Rationale
The Two-Way Map
library is designed using a composite data structure that combines features of a Map and a LinkedList. This choice is driven by the specific requirements of bidirectional lookup and order preservation, ensuring both efficiency and functionality in scenarios where these features are crucial.
Why This Data Structure?
Bidirectional Lookup
- The core of the
Two-Way Map
is built upon two Maps - one for the key-to-value mapping and another for the value-to-key mapping. This structure allows for constant-time (O(1)) lookup in both directions, which is a significant advantage over iterating through an array or a standard map where you would typically achieve O(n) lookup time.
Order Preservation
- In addition to bidirectional lookup, preserving the insertion order is a key requirement for many use cases. To achieve this, the library utilizes a LinkedList. This allows us to maintain the order of elements as they are inserted, which is not possible with standard JavaScript objects or Maps.
Trade-offs
- While this data structure provides significant benefits in terms of functionality, it does come with trade-offs, particularly in terms of memory usage. By maintaining two Maps and a LinkedList, the
Two-Way Map
can consume more memory than a simple Map or object. However, for many applications, this trade-off is justified by the benefits of quick bidirectional access and order preservation.
When to Use Two-Way Map
?
Two-Way Map
is ideal for applications where both the key and value are important for retrieval and where the order of elements matters - for instance, in UI state management, session handling, or complex data transformations.
Alternative Data Structures
- For applications that only require simple key-to-value mapping without the need for reverse lookup or order preservation, a standard Map or object would be more memory-efficient.
- If only order is important and not bidirectional mapping, an Array or a LinkedList might suffice.
Conclusion
The Two-Way Map
library is crafted to fill a specific niche where both bidirectional lookup and order preservation are required. It strikes a balance between performance and functionality, making it a suitable choice for a range of applications where these features provide a tangible benefit.
Contributing
Contributions are always welcome! Feel free to open a pull request or an issue if you have suggestions or find a bug.
License
This project is licensed under the MIT License.