High performance JS map for int-string pairs - javascript

I need a high performance map in Javascript (hashmap or whatever) that maps int(s) to string(s). The map would be used to build some sections of the webpage after dom is ready. I know simple javascript object also works like a map but I need to work with best performance.
I would like to initialize the map with all data pairs just at once by appending a string to the webpage while generating the response page from server.
Any ways how to improve performance of javascript map for int- string pairs or are there any implementations for the same ?
--
Using jQuery 1.7

Ok, I'll post it here since it's more of an answer:
Use an array. Taken into account that any implementation will have to use js primitives and objects, you'll be hard pressed to find something more performant than that.
Arrays in most (all?) implementations of javascript can be sparse. So array.length will return the index of last element + 1, but in sparse case the array will not have all elements allocated and will use object property semantics to access it's elements (meaning, it's effectively a hashtable with ints as keys).
It basically gives you the behavior you're looking for.
In case of negative ints, use a second array.
In relation to a single statement initialization: you can't do it in general, since it bases itself on implicitly knowing the item index.
What you can do is to append something along the lines:
var arr = [];
arr[int1] = val1;
arr[int2] = val2;
arr[int3] = val3;
arr[int4] = val4;
...
arr[intn] = valn;
I mean you have to list (Number, String) pairs somehow anyway.

Please check out this jperf test case, and draw your conclusion.
Objects are also sparse. Arrays are simply specialized objects that account for their own length among other things.

I think you should use the following
var l_map = {};
to add an element use
l_map[<your integer>] = <your string>
and to retrieve is
var l_value = l_map[<your integer>];
This is one way to solve your problem.
The second way is quite simple just use an array (or list) because it stores the values based on position as follows:
var l_array = [];
to add element at the last use : l_array.push(<your string>);
to add element at a specified position : l_array.splice(<position>,0,<your string>);
and to retrieve use : l_array[<posit>];

Related

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)

How can a linq query be converted to JavaScript array containing only values?

I have a JavaScript grid library (it creates a table on the page) that accepts a JavaScript array as input, for rendering in the grid. I'm not certain, however, how to convert a Linq-to-SQL query (against a SQL Server database) to a JavaScript array containing only values.
I tried this, but it included the table column names in the JSON key (and I don't want JSON anyway, I want a JavaScript string array, unless this can be converted to an array?):
JsonConvert.SerializeObject(query)
Example of the format I need to produce:
[1,2,3],[4,5,6]
Environment: .NET Core 3.1
edit: Here is a sample of what I've currently got, this returns the less than desirable JSON (due to the query results being so large, having a JSON key for very element is going to literally double the size of the query):
Devices Table
ID Name
1 iPhone7
2 iPhone8
3 iPhone9
Needed Array (Note: no column names)
[1, "iPhone7"],[2, "iPhone8"],[3, "iPhone9"]
Current C# code in the controller method (returns undesirable key for every element currently)
var query = db.Devices;
var formattedResult = JsonConvert.SerializeObject(query);
return Ok(formattedResult);
Technically, you could do this:
var query = db.Devices.AsEnumerable()
.Select(d => new object[]{d.ID, d.Name});
var formattedResult = JsonConvert.SerializeObject(query);
return Ok(formattedResult);
But then the code on the other end of your request is going to have to translate all those arrays back into objects.
It's rarely worthwhile to complicate your model like this in order to optimize the size of your network traffic. If you're pulling enough items over the wire to make this a performance issue, you're likely to encounter a variety of other performance issues. I would first consider other options, like implementing paging.
Did you try
var query = db.Devices.ToList();
var array = JArray.FromObject(query);
return Ok(formattedResult)

format json data in javascript like a pivot table

I have the the following data being returned by my api.
[{"category":"Amazon","month":"Feb","total":9.75},
{"category":"Amazon","month":"Mar","total":169.44},
{"category":"Amazon","month":"Apr","total":10.69},
{"category":"Amazon","month":"May","total":867.0600000000001},
{"category":"Amazon","month":"Jun","total":394.43999999999994},
{"category":"Amazon","month":"Jul","total":787.2400000000001},
{"category":"Amazon","month":"Aug","total":1112.4400000000003},
{"category":"Amazon","month":"Sep","total":232.86999999999998},
{"category":"Amazon","month":"Oct","total":222.26999999999998},
{"category":"Amazon","month":"Nov","total":306.09999999999997},
{"category":"Amazon","month":"Dec","total":1096.2599999999998}]
I want to format it so that the months are all grouped under each category like this:
[{"category":"Amazon","month":{"Jan":9.75,"Feb":9.75,"Mar":9.75,"Apr":9.75,etc...}]
How can I do this with javascript?
What I'm ultimately trying to do is to display some pivoted data in a table. I'm not sure what the best design is to accomplish this.
Right now, I'm just setting up a table dynamically and adding in the data corresponding to each row. Are there better design patterns for doing this?
You can reduce the array of objects to an object using the categories as keys, and adding the months, and then map it back to an array again
var arr = [{"category":"Amazon","month":"Feb","total":9.75},
{"category":"Amazon","month":"Mar","total":169.44},
{"category":"Amazon","month":"Apr","total":10.69},
{"category":"Amazon","month":"May","total":867.0600000000001},
{"category":"Amazon","month":"Jun","total":394.43999999999994},
{"category":"Amazon","month":"Jul","total":787.2400000000001},
{"category":"Amazon","month":"Aug","total":1112.4400000000003},
{"category":"Amazon","month":"Sep","total":232.86999999999998},
{"category":"Amazon","month":"Oct","total":222.26999999999998},
{"category":"Amazon","month":"Nov","total":306.09999999999997},
{"category":"Amazon","month":"Dec","total":1096.2599999999998}];
var o = arr.reduce( (a,b) => {
a[b.category] = a[b.category] || [];
a[b.category].push({[b.month]:b.total});
return a;
}, {});
var a = Object.keys(o).map(function(k) {
return {category : k, month : Object.assign.apply({},o[k])};
});
console.log(a);
I would take the following approach:
Write down on a piece of paper how to solve the problem (the "algorithm").
Flesh out this algorithm with more details. Sometimes this is called "pseudo-code".
Convert the pseudo-code into JavaScript.
For instance, your algorithm might look like this:
Create a new thing to hold the results.
Loop through the elements in the input.
For each element in the input, update the results thing.
Return the result.
Sometimes it helps to read out the algorithm aloud to yourself. Or animate the algorithm on a blackboard. Or talk through the algorithm with someone nearby.
The pseudo-code might be:
Create a new array containing a new object to hold the results, with a category property set to "Amazon", and a months property set to an empty object.
Loop through the elements in the input array.
For each element, add a new property to the months property of the results object, whose key is the value of the month property from the element, and whose value is the value of the total property from the element.
Return the result.
If you have specific questions about any of those steps, you can research it further, or ask, such as:
How do I create a new array, with an object inside?
How do I loop through the elements of an array?
How do I retrieve a property from an object?
How do I add a new key/value pair to an object?
How do I return the result?
If you are unfamiliar with any of the terms used above--such as array, object, property, key, value, or element--research them and make sure you know what they mean. Knowing and using correct terminology is the first step to successful programming!
When converting your algorithm into JS, write it step by step, and test it at each phase. For instance, start with a version which doesn't loop over the input at all, and make sure it produces a correct output of [{category: "Amazon", month: {}}]. Walk though your code in the debugger at this and each following step--if you don't know how to use the debugger, learning that should be your first priority! If you want to check a little bit of syntax, to make sure it does what you think, just try it out by typing it into the console. If you don't know what the console is, learning that should be another top priority.
All the above assumes that you've got a single Amazon category. If you are going to have multiple categories, and want multiple objects (one for each) in your output array, then start over from the top and write the algorithm and pseudo-code which can handle that.

How to get list of child nodes?

Below, I have attached an image with some console output. What I would like to do is, grab all the numbered nodes (so, 0 and 1, but there could be more or less), and put them into an array (like [0, 1]).
Is this possible?
Use .toArray().
var listOfNodes = $list.toArray();
EDIT: As was pointed out by SterlingArcher, there's a better option in ES6 in the form of Array.from.
var listOfNodes = Array.from($list);
You can use a simple for-loop
To go through these arrays just don't use forEach, with that you will go through every property but you want the numbers only
Jquery uses a combination of arrays and associative array (objects in Javascript)
So it has auto incremented keys and words as keys

javascript: array of object for simple localization

I need to implement a simple way to handle localization about weekdays' names, and I came up with the following structure:
var weekdaysLegend=new Array(
{'it-it':'Lunedì', 'en-us':'Monday'},
{'it-it':'Martedì', 'en-us':'Tuesday'},
{'it-it':'Mercoledì', 'en-us':'Wednesday'},
{'it-it':'Giovedì', 'en-us':'Thursday'},
{'it-it':'Venerdì', 'en-us':'Friday'},
{'it-it':'Sabato', 'en-us':'Saturday'},
{'it-it':'Domenica', 'en-us':'Sunday'}
);
I know I could implement something like an associative array (given the fact that I know that javascript does not provide associative arrays but objects with similar structure), but i need to iterate through the array using numeric indexes instead of labels.
So, I would like to handle this in a for cycle with particular values (like j-1 or indexes like that).
Is my structure correct? Provided a variable "lang" as one of the value between "it-it" or "en-us", I tried to print weekdaysLegend[j-1][lang] (or weekdaysLegend[j-1].lang, I think I tried everything!) but the results is [object Object]. Obviously I'm missing something..
Any idea?
The structure looks fine. You should be able to access values by:
weekdaysLegend[0]["en-us"]; // returns Monday
Of course this will also work for values in variables such as:
weekdaysLegend[i][lang];
for (var i = 0; i < weekdaysLegend.length; i++) {
alert(weekdaysLegend[i]["en-us"]);
}
This will alert the days of the week.
Sounds like you're doing everything correctly and the structure works for me as well.
Just a small note (I see the answer is already marked) as I am currently designing on a large application where I want to put locals into a javascript array.
Assumption: 1000 words x4 languages generates 'xx-xx' + the word itself...
Thats 1000 rows pr. language + the same 7 chars used for language alone = wasted bandwitdh...
the client/browser will have to PARSE THEM ALL before it can do any lookup in the arrays at all.
here is my approach:
Why not generate the javascript for one language at a time, if the user selects another language, just respond(send) the right javascript to the browser to include?
Either store a separate javascript with large array for each language OR use the language as parametre to the server-side script aka:
If the language file changes a lot or you need to minimize it per user/module, then its quite archivable with this approach as you can just add an extra parametre for "which part/module" to generate or a timestamp so the cache of the javascript file will work until changes occures.
if the dynamic approach is too performance heavy for the webserver, then publish/generate the files everytime there is a change/added a new locale - all you'll need is the "language linker" check in the top of the page, to check which language file to server the browser.
Conclusion
This approach will remove the overhead of a LOT of repeating "language" ID's if the locales list grows large.
You have to access an index from the array, and then a value by specifying a key from the object.
This works just fine for me: http://jsfiddle.net/98Sda/.
var day = 2;
var lang = 'en-us';
var weekdaysLegend = [
{'it-it':'Lunedì', 'en-us':'Monday'},
{'it-it':'Martedì', 'en-us':'Tuesday'},
{'it-it':'Mercoledì', 'en-us':'Wednesday'},
{'it-it':'Giovedì', 'en-us':'Thursday'},
{'it-it':'Venerdì', 'en-us':'Friday'},
{'it-it':'Sabato', 'en-us':'Saturday'},
{'it-it':'Domenica', 'en-us':'Sunday'}
];
alert(weekdaysLegend[day][lang]);

Categories