In programming, a dictionary is like a real-life dictionary, where you look up a ‘word’ (key) to find its ‘meaning’ (value). TypeScript, like JavaScript, doesn’t have a built-in Dictionary type, but we can use an object to achieve the same functionality. Why do we use it? Simply because it’s a very efficient way to store and retrieve data where the order is not important, but the link between keys and values is.
Defining a Dictionary in TypeScript
To define a dictionary in TypeScript, we use an object. The type notation is:
{ [key: type]: valueType }
.
Here’s a simple example:
let dictionary: { [key: string]: number } = {};
In this code, we have a dictionary where the keys are strings and the values are numbers.
TypeScript Dictionary Operations
With the dictionary defined, let’s see how we can work with it:
Adding Key-Value Pairs
We can add new key-value pairs like this:
dictionary['apple'] = 5;
dictionary['banana'] = 10;
Accessing Dictionary Values
We can access the values by their keys:
console.log(dictionary['apple']); // Output: 5
console.log(dictionary['banana']); // Output: 10
Removing Key-Value Pairs
We can remove key-value pairs using the delete
keyword:
delete dictionary['apple'];
Modifying Values
We can modify a value by assigning a new value to a key:
dictionary['banana'] = 20;
Checking if a Key Exists
We can check if a key exists using the in
keyword:
if ('apple' in dictionary) {
console.log('apple exists');
} else {
console.log('apple does not exist');
}
Type Safety with Dictionary Type
One of the main benefits of TypeScript is its type safety. This means that TypeScript will ensure that we only use our dictionary with the types we defined (string keys and number values in our example). So, if we tried to set a key or a value to a wrong type, TypeScript would show an error:
dictionary['orange'] = 'a lot'; // Error: Type 'string' is not assignable to type 'number'.
Advanced Dictionary Types
As we get more comfortable with TypeScript dictionaries, we can explore advanced features:
Dictionaries with Enum Keys
In TypeScript, we can use an enum
as a key in our dictionary. This can provide additional type safety and code clarity:
enum Fruit {
Apple,
Banana,
Orange
}
let fruitBowl: { [K in Fruit]?: number } = {};
fruitBowl[Fruit.Apple] = 5;
fruitBowl[Fruit.Banana] = 10;
Readonly Dictionaries
TypeScript allows us to define a dictionary as readonly, which means that once we define it, we can’t change it:
const readonlyDictionary: Readonly<{ [key: string]: number }> = {
apple: 5,
banana: 10
};
readonlyDictionary['apple'] = 10; // Error: Index signature in type 'Readonly<{ [key: string]: number; }>' only permits reading.
Nested Dictionaries
TypeScript also supports dictionaries within dictionaries. These can be useful for more complex data structures:
let nestedDictionary: { [key: string]: { [key: string]: number } } = {
fruit: {
apple: 5,
banana: 10
},
vegetable: {
carrot: 20,
potato: 25
}
};
Common Use Cases of TypeScript Dictionaries
Dictionaries are used in a lot of different scenarios. For example:
Storing Data for Fast Lookup
If you want to keep track of the count of each word in a list of words, a dictionary would be a perfect choice. Keys can be the words, and values can be the counts.
Grouping by a Key
If you have a list of objects and you want to group them by a certain property, you can use a dictionary. The property value can be the key, and the value can be an array of objects that have that property value.
Counting Occurrences of Elements
Dictionaries are also excellent for counting the occurrences of elements in a list.
Let’s see some interesting uses of dictionaries to solve some interesting problems:
Usage example: Word Frequency Counter
This is a very straightforward yet effective use of dictionaries. Given a list or a stream of words, we can use a dictionary to keep track of the frequency of each word. The word itself is the key and the frequency count is the value. Each time a word appears, we increment its count in the dictionary. This forms the basis of many text analysis algorithms. Absolutely, here’s an example of how you could solve the Word Frequency Count problem using a TypeScript dictionary:
function wordFrequencyCount(text: string): { [word: string]: number } {
// Create an empty dictionary
let frequencyDictionary: { [word: string]: number } = {};
// Convert text to lower case and split it into words
let words = text.toLowerCase().split(/\s+/);
// Iterate over each word
for (let word of words) {
// If word exists in dictionary, increment its count, else set its count to 1
if (word in frequencyDictionary) {
frequencyDictionary[word]++;
} else {
frequencyDictionary[word] = 1;
}
}
// Return the frequency dictionary
return frequencyDictionary;
}
let text = "Hello world! This is a test. Hello again. Is this a test?";
let frequencies = wordFrequencyCount(text);
console.log(frequencies);
In this code, we first create an empty dictionary frequencyDictionary
. We then split the text into words, iterating over each one. If a word is already a key in our dictionary, we increment its value; if not, we add it to the dictionary with a value of 1.
Finally, we return our dictionary. If you run this code with the example string "Hello world! This is a test. Hello again. Is this a test?"
, the output will be a dictionary with the frequency of each word in the text.
Please note that this is a basic version of word frequency count, for simplicity it just considers space for word splitting. In a more robust solution, you would want to consider punctuation and common word filtering (like removing ‘a’, ‘is’, ’the’ etc). Also this doesn’t differentiate words like ’test’ and ’test?’ because of the punctuation.
Usage example: Subarray Sum Equals K
Given an array of integers and an integer K, you need to find the total number of continuous subarrays whose sum equals to K. This problem can be solved by using a dictionary to store the cumulative sum of the elements and the number of times each sum occurs. If a cumulative sum up to index j is equal to sum, we know that there are exactly sum occurrences of that sum, and we add this to our total count.
function subarraySum(nums: number[], k: number): number {
let count = 0;
let sum = 0;
let sumFrequency: { [sum: number]: number } = { 0: 1 };
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
if ((sum - k) in sumFrequency) {
count += sumFrequency[sum - k];
}
if (sum in sumFrequency) {
sumFrequency[sum]++;
} else {
sumFrequency[sum] = 1;
}
}
return count;
}
let nums = [1, 1, 1];
let k = 2;
console.log(subarraySum(nums, k)); // Output: 2
In this function, sumFrequency
is a dictionary that stores the cumulative sum of the array elements up to the current index as keys and the number of times each sum occurs as values.
The sum
variable keeps track of the cumulative sum of the array elements. If the difference sum - k
exists in the dictionary, it means that there are one or more subarrays ending at the current index that sum to k
, so we increase count
by the frequency of sum - k
in the dictionary.
Then, we update the frequency of the current sum
in the dictionary. If sum
is already a key in the dictionary, we increment its value, otherwise, we set its value to 1.
Finally, we return count
, which is the total number of continuous subarrays whose sum equals to k
.
In this example, the input array is [1, 1, 1]
and k
is 2. The output is 2 because there are two subarrays [1, 1]
and [1, 1]
(starting from the second index) that sum to 2.
Common Pitfalls and How to Avoid Them
While dictionaries are very powerful, there are some pitfalls to be aware of:
Handling Undefined Values
If you try to access a value using a key that doesn’t exist in the dictionary, you’ll get undefined
. Always check if a key exists before using its value.
Iterating Over a Dictionary
To iterate over a dictionary, you can use for..in
loop or Object.keys()
method. Be aware that the order of the keys is not guaranteed.
Dealing with Unknown Keys
If you don’t know whether a key exists in a dictionary, use the in
keyword to check before using it.
Comparison with Other Data Structures
Compared to other data structures:
Dictionary vs Array
Arrays are good when you have a list of items, and the order matters. Dictionaries are better when you need to associate keys with values and lookup speed is important.
Dictionary vs Set
Sets are good when you have a list of unique items, and you only need to check membership. Dictionaries are better when you need to associate keys with values.
Dictionary vs Map
In JavaScript/TypeScript, a Map is a more advanced structure that can have any type as a key, whereas in a dictionary (plain object), keys can be only strings or symbols. Maps maintain the insertion order, whereas dictionaries do not.