LRU cache implementation in Javascript - javascript

Java has LinkedHashMap which gets you 99% there to an LRU cache.
Is there a Javascript implementation of an LRU cache, preferably from a reputable source, that is:
understandable
efficient (amortized O(1) get/put/delete)
? I've been searching on the web but couldn't find one; I thought I found one on Ajax Design Patterns but it glosses over the sendToTail() method and has O(n) performance (presumably, since the queue and associative array are split up).
I suppose I could write my own, but I've learned the hard way that reinventing the wheel for core algorithms can be hazardous to one's health :/

Map should be O(1) in most implementations average case. Since Map keeps insertion order, adding a bit of code around it will get you a LRU and for most uses this should be plenty fast.
I needed a simple LRU cache for a small number of expensive operations (1 second). I felt better about copy-pasting some small code rather than introducing something external, but since I didn't find it I wrote it:
class LRU {
constructor(max = 10) {
this.max = max;
this.cache = new Map();
}
get(key) {
let item = this.cache.get(key);
if (item) {
// refresh key
this.cache.delete(key);
this.cache.set(key, item);
}
return item;
}
set(key, val) {
// refresh key
if (this.cache.has(key)) this.cache.delete(key);
// evict oldest
else if (this.cache.size == this.max) this.cache.delete(this.first());
this.cache.set(key, val);
}
first() {
return this.cache.keys().next().value;
}
}
Usage:
> let cache = new LRU(3)
> [1, 2, 3, 4, 5].forEach(v => cache.set(v, 'v:'+v))
> cache.get(2)
undefined
> cache.get(3)
"v:3"
> cache.set(6, 6)
> cache.get(4)
undefined
> cache.get(3)
"v:3"

This:
https://github.com/monsur/jscache
seems to fit you case although setItem (i.e. put) is O(N) in the worst case, that happens if the cache is filled up on insertion. In this case the cache is searched to purge expired items or least recently used items. getItem is O(1) and the expiry is handled on the getItem operation (i.e. if the item being fetched is expired, removes it and returns null).
The code is compact enough to be easily understood.
P.S. It might be useful to add to the constructor the option to specify the fillFactor, which is fixed to 0.75 (meaning that when the cache is purged it's size is reduced at least to 3/4th of the maximum size)

This is worth a mention:
https://github.com/rsms/js-lru
The core set of functions are O(1) and the code is heavily commented (with ASCII art too!)

The monsur.com implementation is O(n) on insertion only because it has items which actually expire on real world time. It is not a simple LRU. If you only care about maintaining the most recently used items without regard to real world time, this can be done in O(1). A queue, implemented as a doubly linked list, is O(1) for insertion or deletion from the end, and this is all you should need for a cache. As for lookup, a hash map, which javascript makes pathetically easy, should be good for nearly O(1) lookup (assuming the javascript engine uses a good hashmap, that's implementation dependent of course). So you have a linked list of items with a hash map pointing to the items. Manipulate the ends of the linked list as needed to put new items and requested items on one end and remove old items from the other end.

This library runtime-memcache implements lru and a few other caching schemes in javascript.
It uses modified Doubly Linked List to achieve O(1) for get, set and remove. You can check out the implementation which is pretty simple.

It's not an LRU cache, but I've got my own linked map implementation. As it uses a JS objects as store, it'll have similar performance characteristics (the wrapper objects and hash function impart a performance penalty).
Currently, documentation is basically non-existant, but there's a related SO answer.
The each() method will pass the current key, the current value and a boolean indicating if there are more elements as arguments to the callback function.
Alternatively, looping can be done manually via
for(var i = map.size; i--; map.next()) {
var currentKey = map.key();
var currentValue = map.value();
}

I am aware that this is an old question but adding a link for future refrence.
Check out https://github.com/monmohan/dsjslib . This has a LRU Cache implementation in addition to some other data structures. Such caches (and this one too) maintain doubly linked list of cache entries in LRU order i.e. entries move to the head as they are accessed and are removed from tail when they are reclaimed (say by expiry or because size limit was reached). Its O(1) since it only involves constant number of pointer manipulations.

I improve #odinho's answer to fit this leetcode question
change if (item) to if (item != undefined) to fit value === 0 case
following is my code:
class LRUCache {
constructor(max = 10) {
this.max = max
this.cache = new Map()
}
get(key) {
let item = this.cache.get(key)
if (item !== undefined) {
// refresh key
this.cache.delete(key)
this.cache.set(key, item)
}
return item === undefined ? -1 : item
}
put(key, val) {
// refresh key
if (this.cache.has(key)) this.cache.delete(key)
// evict oldest
else if (this.cache.size == this.max) this.cache.delete(this.first())
this.cache.set(key, val)
}
first() {
return this.cache.keys().next().value
}
}

Since we need read, write, update and delete operations in O(1), we use two data structures.
An Object(or Map)in JavaScript provides retrieval in O(1).
A Doubly LinkedList(Custom data structure we create) makes below functionalities in O(1)
change position of the most used element to the top
delete least used element from cache on reaching cache limit.
The custom implementation of Doubly LinkedList and Least Recently Used cache with clear explanation is given below.
https://medium.com/dsinjs/implementing-lru-cache-in-javascript-94ba6755cda9

External package/library is not required, we can write our own code to implement LRU in javascript, Please refer https://dev.to/udayvunnam/implementing-lru-cache-in-javascript-3c8g site for details.

Related

Testing if an array or linked list is a palindrome

I am doing a problem on Leetcode to write a function which checks to see if a supplied array is a palindrome. They seem to expect the solution to involve creating a linked list from the array and then using the linked list to check if its contents are a palindrome.
Am I right in assuming that the reason for using a linked list (other than to test your programming skills) is that it enables a more efficient (ie takes less processing power) solution than working solely with arrays?
What I find counter intuitive about that is the fact that the function takes an array as its argument so, the data is already in an array. My thinking is that it must take as much processing power to get the array into a linked list as it would take to just go through the elements in the array from each end checking each pair to see if they are equal.
In order to make the linked list you would have to access all the array elements. The only thing I can think is that accessing elements from the end of array might be more 'expensive' than from the front.
I have put my code for solving the problem with an array below:
function isPalindrome(array){
const numberOfTests = Math.floor(array.length/2);
for(let i = 0; i < numberOfTests; i++){
let j = array.length - 1 - i;
if(array[i] !== array[j]){
return false;
}
}
return true;
}
console.log(isPalindrome([1,1,1,2]))
I guess my question is why are they suggesting using linked lists to solve this problem other than to test programming skills? Is there something about my function which is less efficient than using a linked list to accomplish the same task?
Edit:
The code editor for the question is pre-populated with:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* #param {ListNode} head
* #return {boolean}
*/
var isPalindrome = function(head) {
};
Also from the question:
The number of nodes in the list is in the range [1, 105].
0 <= Node.val <= 9
Follow up: Could you do it in O(n) time and O(1) space?
I am not exactly sure what this all means but I interpreted it as suggesting there are performance issues involve with the algorithm and that using linked lists would be a good way to address them.
The problem is at: https://leetcode.com/problems/palindrome-linked-list/
The code challenge is saying that you are "given the head of a singly linked list". So it is not an array. The misunderstanding may come from the way that LeetCode represents a linked list: they use an array notation for it. But be assured that your function will be called with a linked list, not an array.
Am I right in assuming that the reason for using a linked list (other than to test your programming skills) is that it enables a more efficient (ie takes less processing power) solution than working solely with arrays?
No, it is only for testing programming skills.
What I find counter intuitive about that is the fact that the function takes an array as its argument
This is where you got the code challenge wrong. Look at the description ("Given the head of a singly linked list"), and look at the template code you get to start from (the parameter is named head, not array).
Is there something about my function which is less efficient than using a linked list to accomplish the same task?
Your function will not work. The argument does not have a length property since it is not an array. The argument is an instance of ListNode or null.
In your code you included a call of your function. But that is not how LeetCode will call your function. It will not be called like:
isPalindrome([1, 2, 2, 1])
But like:
isPalindrome(new ListNode(1,
new ListNode(2,
new ListNode(2,
new ListNode(1)))))
From the way you have described it, no matter if we analyse this issue via big-O time complexity or empirical performance, there is no real reason to convert it to a linked list first. It will definitely slow your program down.
This is relatively easy to comprehend: in order to create the linked list, you have to access the whole array. How is this slower than accessing the array elements to determine if it is a palindrome? In terms of array access operations, we are accessing each of the array elements at most once (ideally), in each case. However, with the linked list approach we also have to spend time to create the linked list and then determine if that is a palindrome.
It's like if you're doing a math question, instead of doing it on the piece of paper it was given on, copying it to a piece of parchment first and doing it there. You aren't saving time.
Albeit, the time complexity for both should be O(N) worst-case, and their runtimes should not differ drastically as the difference is only a small constant.
Converting to a linked list is probably only for demonstrative reasons, not performance reasons.
I'll start by reiterating my comment for some context:
One of LeetCode's goals is to help you learn common algorithms, programming patterns, and data structures (language agnostic) in a puzzle-oriented way. There's nothing wrong with your approach, except that the input is not an array, so it is not valid for the problem constraints. The main purpose of this problem is for you to understand what a singly-linked list data structure is and to begin to learn about big O notation.
Based on the details of your question and your follow-up comments, it sounds like you're having trouble with the first part: understanding the structure of a singly-linked list. This is understandable if your experience is in JavaScript: a singly-linked list is not a common data structure in comparison to arrays.
Included in the description details of the problem that you linked to, is the following:
Example 1:
Input: head = [1,2,2,1]
Output: true
The way that the head input argument is shown in the text uses the same syntax as an array of numbers in JavaScript. This is only an abstract (theoretical way of looking at things) representation of a linked list. It does NOT mean literally:
const head = [1, 2, 2, 1];
A linked list is a nested structure of nodes, each having a value and (maybe) a child node. The head input example actually looks like this JavaScript data structure:
const head = {
val: 1,
next: {
val: 2,
next: {
val: 2,
next: {
val: 1,
next: null,
},
},
},
};
This might seem new/confusing to you (and that's ok). This data structure is much more common in some other languages. There will be other problems on LeetCode that will be more familiar to you (and less familiar to programmers who work in those languages): it's part of the challenge and enjoyment of learning.
If the site content maintainers ever consider updating the problem details for each code puzzle, it might be a good idea to provide custom description information based on which language is selected, so that this kind of confusion happens less often.

javascript - Set vs Map - which is faster?

Set and Map both are newer data types in es6 and for certain situations both can be used.
e.g - if i want to store all unique elements, i can use Set as well as Map with true as value.
const data: string[] ;
// console.log('data', data[0])
const set = new Set();
const map = new Map<string, boolean>();
data.forEach((item) => {
map.set(item, true);
});
data.forEach((item) => {
set.add(item);
});
Both works, but i was wondering which one is faster ?
Update 1
I am looking for which of the data structure is faster in case of storing data.
checking if value exist using -
map.has(<value>)
set.has(<value>)
deleting values
Also i can understand true is redundant and not used anywhere, but i am just trying to show how map and set can be used alternatively.
What matters is speed.
In the most basic sense:
Maps are for holding key-value pairs
Sets are for holding values
The true in your map is completely redundant ... if a key exists, that automatically implies, that it is true/exists - so you will never ever need to use the value of the key-value pair in the map (so why use the map at all, if you're never gonna make use of what it is actually for? - to me that sounds like a set/array with extra steps)
If you just want to store values use an array or set. - Which of the two depends on what you are trying to do.
The question of "which is faster" can't really be answered properly, because it largely depends on what you are trying to do with the stored values. (What you are trying to do also determines what data structure to use)
So choose whatever data structure you think fits your needs best, and when you run into a problem that another would fix, you can always change it later/convert from one into another.
And the more you use them and the more you see what they can and can not do, the better you'll get at determining which to use from the start (for a given problem)

accessing and removing objects by ID

I have certain requirements , I wanted to do the following in quickest way as possible.
I have 1000's of objects like below
{id:1,value:"value1"} . . {id:1000,value:"value1000"}
I want to access above objects by id
I want to clean the objects Lesser than certain id every few minutes (Because it generates 1000's of objects every second for my high frequency algorithm)
I can clean easily by using this.
myArray = myArray.filter(function( obj ) {
return obj.id > cleanSize;
});
I can find the object by id using
myArray.find(x => x.id === '45');
Problem is here , I feel that find is little slower when there is larger sets of data.So I created some objects of object like below
const id = 22;
myArray["x" + id] = {};
myArray["x" + id] = { id: id, value:"test" };
so I can access my item by id easily by myArray[x22]; , but problem is i am not able find the way to remove older items by id.
someone guide me better way to achieve the three points I mentioned above using arrays or objects.
The trouble with your question is, you're asking for a way to finish an algorithm that is supposed to solve a problem of yours, but I think there's something fundamentally wrong with the problem to begin with :)
If you store a sizeable amount of data records, each associated with an ID, and allow your code to access them freely, then you cannot have another part of your code dump some of them to the bin out of the blue (say, from within some timer callback) just because they are becoming "too old". You must be sure nobody is still working on them (and will ever need to) before deleting any of them.
If you don't explicitly synchronize the creation and deletion of your records, you might end up with a code that happens to work (because your objects happen to be processed quickly enough never to be deleted too early), but will be likely to break anytime (if your processing time increases and your data becomes "too old" before being fully processed).
This is especially true in the context of a browser. Your code is supposed to run on any computer connected to the Internet, which could have dozens of reasons to be running 10 or 100 times slower than the machine you test your code on. So making assumptions about the processing time of thousands of records is asking for serious trouble.
Without further specification, it seems to me answering your question would be like helping you finish a gun that would only allow you to shoot yourself in the foot :)
All this being said, any JavaScript object inherently does exactly what you ask for, provided you're okay with using strings for IDs, since an object property name can also be used as an index in an associative array.
var associative_array = {}
var bob = { id:1456, name:"Bob" }
var ted = { id:2375, name:"Ted" }
// store some data with arbitrary ids
associative_array[bob.id] = bob
associative_array[ted.id] = ted
console.log(JSON.stringify(associative_array)) // Bob and Ted
// access data by id
var some_guy = associative_array[2375] // index will be converted to string anyway
console.log(JSON.stringify(some_guy)) // Ted
var some_other_guy = associative_array["1456"]
console.log(JSON.stringify(some_other_guy)) // Bob
var some_AWOL_guy = associative_array[9999]
console.log(JSON.stringify(some_AWOL_guy)) // undefined
// delete data by id
delete associative_array[bob.id] // so long, Bob
console.log(JSON.stringify(associative_array)) // only Ted left
Though I doubt speed will really be an issue, this mechanism is about as fast as you will ever get JavaScript to run, since the underlying data structure is a hash table, theoretically O(1).
Anything involving array methods like find() or filter() will run in at least O(n).
Besides, each invocation of filter() would waste memory and CPU recreating the array to no avail.

Create a unique ID for each element of array with JavaScript?

I have a use case where I want to assign unique ids to each element of array while iterating over it. Note, This array contains duplicate values. I want to use index as a key in react element, but linter rules do not allow me to use index as a key.
I thought of using System tics. Is there a way I can get system ticks so that on every instruction execution, I get a new value?
If yes, what is the recommended precision?
I would suggest to use neither indices nor system ticks as both options take you away from the functionality that the key is supposed to provide.
In the documentation it says: "Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity"
So there are a variety of options:
You can create a function to generate unique keys/ids/numbers/strings and use that
You can make use of existing npm packages like uuid, uniqid, etc
You can also generate random number like new Date().getTime(); and prefix it with something from the item you're iterating to guarantee its uniqueness
Lastly, you can use the unique ID you get from the database, if you get it (hard to say without seeing your data)
However: Keys should be stable, predictable, and unique. Unstable keys (like those produced by Math.random()) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.
You can read more here: https://reactjs.org/docs/reconciliation.html#keys
So there is no perfect answer for that. It depends on your use case...
Even though #Archer 's approach might already be feasible enough, I provide this solution that I mostly use in cases like the ones described by the OP ...
var createId = (
/* [https://github.com/broofa/node-uuid] - Robert Kieffer */
(window.uuid && (typeof window.uuid.v4 === 'function') && window.uuid.v4)
/* [https://gist.github.com/jed/982883] - Jed Schmidt */
|| function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
);
console.log('createId() : ', createId());
console.log('createId() : ', createId());
console.log('createId() : ', createId());
.as-console-wrapper { max-height: 100%!important; top: 0; }

Backbone multi-collection global search

I'm playing around with the idea of creating a global search that allows me to find any model in any of a number of collections by any of the model's attributes. For example:
I have the following collections:
Users
Applications
Roles
I don't know ahead of time what attributes each User, Applicaion and Role will have but for illustration purposes lets say I have:
User.name
User.last_name
User.email
Application.title
Application.description
Role.name
Role.description
Now, lets say I create a model called Site with a method called search. I want Site.search(term) to search through all the items in each collection where term matches any of the attributes. In essence, a global model search.
How would you suggest I approach this? I can brute-force it by iterating through all the collections' models and each model's attributes but that seems bloated and inefficient.
Any suggestions?
/// A few minutes later...
Here's a bit of code I tried just now:
find: function(query) {
var results = {}; // variable to hold the results
// iterate over the collections
_.each(["users", "applications", "roles"], _.bind(function(collection){
// I want the result to be grouped by type of model so I add arrays to the results object
if ( !_.isUndefined(results[collection]) || !_.isArray(results[collection]) ) {
results[collection] = [];
}
// iterate over the collection's models
_.each(this.get(collection).models, function(model){
// iterate over each model's attributes
_.each(model.attributes, function(value){
// for now I'm only considering string searches
if (_.isString(value)) {
// see if `query` is in the attribute's string/value
if (value.indexOf(query) > -1) {
// if so, push it into the result's collection arrray
results[collection].push(model);
}
};
});
});
// a little cleanup
results[collection] = _.compact(results[collection]);
// remove empty arrays
if (results[collection].length < 1) {
delete results[collection];
}
},this));
// return the results
return results;
}
This yields the expected result and I suppose it works fine but it bothers me that I'm iterating over three arrays. there may not be another solution but I have a feeling there is. If anyone can suggest one, thank you! Meanwhile I'll keep researching.
Thank you!
I would strongly discourage you from doing this, unless you have a very limited set of data and performance is not really a problem for you.
Iteration over everything is a no-no if you want to perform search. Search engines index data and make the process feasible. It is hard to build search, and there is no client-side library that does that effectively.
Which is why everybody is doing searching on the server. There exist easy (or sort of) to use search engines such as solr or the more recent and my personal preference elasticsearch. Presumably you already store your models/collections on the server, it should be trivial to also index them. Then searching becomes a question of making a REST call from your client.

Categories