Statement
Solution
Naive approach
A naive approach to create an array-like data structure that supports snapping its values ​​at different times would be to create a list to store the array values ​​in each snapshot. We will increment the counter to keep track of the current snapshot ID. To take a snapshot, we will copy the current list and add it to the list of snapshots. To get the value on a given index and the snapshot ID, we access the given snapshot ID and the corresponding element in the snapshot list for the index.
For example, we want to create an array of length 5 and take three snapshots of its values at different times. We will create a list to store the values of the array at each snapshot, as well as a counter to keep track of the current snapshot ID:
arr = [0, 0, 0, 0, 0]
To set a value at a given index, we can update the corresponding element in the list:
arr[2] = 4
To take a snapshot, we will create a copy of the current list and add it to the list of snapshots. After taking three snapshots, the snapshots list will contain the following:
snapshots = [[0, 0, 0, 0, 0], [0, 0, 4, 0, 0], [0, 0, 4, 0, 0], [0, 0, 4, 0, 0]]
This naive approach will work for small arrays and a small number of snapshots. When the size of the array and the number of snapshots increases, this approach can become inefficient, since it requires copying the entire list for each snapshot. Let’s see if we can use the Custom Data Structures pattern to reduce the complexity of our solution.
Optimized approach using nested dictionaries
To solve this problem, we will start by creating a dictionary named Node Value. The node value will hold all the values, along with the nodes, at different times in further subdictionaries. The keys to the Node Value dictionary are the Snapshot IDs. For a given key, the values are also dictionaries. These inner dictionaries have node IDs as keys and the node’s value as values.
The Node Value dictionary keeps track of values that are set until the latest snapshot, rather than storing the entire array for each snapshot, as in the naive approach. This allows for more efficient memory usage and faster performance, especially for large arrays and a large number of snapshots.