Javascript equivalent of VBS redim preserve - javascript

I'm trying to rewrite some old VBScript as Javascript for an ASP.NET application and there is one line I'm not sure how to translate, and I'm not even entirely positive what it's doing.
The application essentially allows the user to enter in a new employee number to add to the database and then assign it user permissions. Don't ask me why the code is such a mess, I didn't write it originally, I'm just trying to make it work in Chrome
here's the relevant code that i've managed to translate so far:
if(form1.txtEmpno.value != ""){
var oOption;
oOption = document.createElement("OPTION");
oOption.text=form1.txtEmpno.value;
oOption.value=form1.txtEmpno.value;
form1.lstActive.add (oOption);
oOption = document.createElement("OPTION");
oOption.text="";
oOption.value="";
form1.lstPerms.add (oOption);
redim preserve arrUsers(1,ubound(arrUsers,2)+1);
arrUsers(0,ubound(arrUsers,2)) = form1.txtEmpno.value;
arrUsers(1,ubound(arrUsers,2)) = "";
form1.txtEmpno.value = "";
oOption = null;
}
here's the line in question:
redim preserve arrUsers(1,ubound(arrUsers,2)+1);

MSDN defines ReDim [Preserve] varname(subscripts) as:
The ReDim statement is used to size or resize a dynamic array that has already been formally declared using a Private, Public, or Dim statement with empty parentheses (without dimension subscripts). You can use the ReDim statement repeatedly to change the number of elements and dimensions in an array.
If you use the Preserve keyword, you can resize only the last array dimension, and you can't change the number of dimensions at all. For example, if your array has only one dimension, you can resize that dimension because it is the last and only dimension. However, if your array has two or more dimensions, you can change the size of only the last dimension and still preserve the contents of the array.
Arrays in JavaScript have different semantics to VBScript's arrays, especially in that they're actually closer to a vector than a true array, furthermore JavaScript does not provide for true N-dimensional arrays: instead you use staggered-arrays (arrays-within-arrays). Which means your VBScript cannot be syntactically converted to JavaScript.
Here's your relevant code in VBScript:
ReDim Preserve arrUsers(1,ubound(arrUsers,2)+1)
arrUsers(0,ubound(arrUsers,2)) = form1.txtEmpno.value
arrUsers(1,ubound(arrUsers,2)) = ""
We see that arrUsers is a 2-dimensional array. This will need to be converted into a staggered array, but you haven't posted the code that defines and initializes arrUsers, nor how it is used later on, so I can only work from making assumptions.
It looks to be adding 1 element to the last dimension, but the code only seems to use the extra space in the [1] subscript (i.e. it only wants the extra dimensional space for certain values of the 0th dimension instead of all values), which makes this simpler as you don't need to iterate over every 0th-dimension subscript.
JavaScript arrays have numerous function-properties that we'll use, in particular push: which appends an element to the end of an array (internally growing the buffer if necessary), and pop which removes the last (highest-indexed) element from an array (if an array is empty, it's a NOOP):
var arrUsers = [ [], [] ]; // empty, staggered 2-dimensional array
...
arrUsers[0].push( form1.txtEmpno.value );
arrUsers[1].pop();
Much simpler.
However, if this array is just part of some internal model to store and represent data then you should take advantage of JavaScript object-prototypes instead of using array indexes, as that makes the code self-describing, for example:
var User = function(empNo, name) {
this.employeeNumber = empNo;
this.name = name;
};
var users = [];
users.push( new User(1, "user 1") );
users.push( new User(23, "user 23") );
...
for(var i = 0; i < users.length; i++ ) {
alert( users[i].name );
}

Related

How do I split/slice a leaflet L.layerGroup into mutliple L.layerGroup(s)?

I'm using leafletjs to draw a line from marker to marker. But the markers are grouped into sets, each with its own name. I get the data from MySQL with PHP and create;
var OBJMarkerList = L.layerGroup([W0DLK01,W0DLK02,W0DLK03,W0DLK04,W0DLK05,WA0TJT01,WA0TJT02,WA0TJT03,WA0TJT04,WA0TJT05,WA0TJT06,WA0TJT07,WA0TJT08,WA0TJT09,]);
Notice the name changes.
But I need to pass it into a function one part at a time in order to change the color of the line. So while I have the above OBJMarkerList what I really need is;
var W0DLKOBJMarkerList = L.layerGroup([W0DLK01,W0DLK02,W0DLK03,W0DLK04,W0DLK05,]);
And another for the other set of values, WA0TJTOBJMarkerList.
I created an array of the names;
const allnameBounds = (['W0DLKOBJMarkerList','WA0TJTOBJMarkerList']);
But its literally just the names and the function (below) will not accept it as input to convert to the x,y coordinates I need.
function connectTheDots(data){
var c = [];
for(i in data._layers) {
var x = data._layers[i]._latlng.lat;
var y = data._layers[i]._latlng.lng;
c.push([x, y]);
}
return c;
}
How can I split the L.layerGroup into two or any number of parts based on the variable names given? There will usually be more than just two, this is a simplified example.
I tried iterating over the allnameBounds array in all the usual ways and while the looping works to extract the name, the function does not process it like the leaflet object it is.
I also went back to the MySQL/PHP and tried to create a stand alone for each name, that's fine but I still need another list of the L.layerGroup names to iterate over.
Spliting or slicing the combined seemed the only answer. I just don't know how to get there.
Can someone give me a better way or show me how to split the overall list?

Checking if element exists in array without iterating through it

my array:
tempListArray = "[{"id":"12","value":false},{"id":"10","value":false},{"id":"9","value":false},{"id":"8","value":false}]";
To check if an element exists I would do this:
for (var i in tempListArray) {
//check flag
if (tempListArray[i].id == Id) {
flagExistsLoop = 1;
break;
}
}
Is there anyway, I can check if an Id exists without looping through the whole array. Basically I am worried about performance if say I have a 100 elements.
Thanks
No, without using custom dictionary objects (which you seriously don't want to for this) there's no faster way than doing a 'full scan' of all contained objects.
As a general rule of thumb, don't worry about performance in any language or any situation until the total number of iterations hits 5 digits, most often 6 or 7. Scanning a table of 100 elements should be a few milliseconds at worst. Worrying about performance impact before you have noticed performance impact is one of the worst kinds of premature optimization.
No, you can't know that without iterating the array.
However, note for...in loops are a bad way of iterating arrays:
There is no warranty that it will iterate the array with order
It will also iterate (enumerable) non-numeric own properties
It will also iterate (enumerable) properties that come from the prototype, i.e., defined in Array.prototype and Object.protoype.
I would use one of these:
for loop with a numeric index:
for (var i=0; i<tempListArray.length; ++i) {
if (tempListArray[i].id == Id) {
flagExistsLoop = 1;
break;
}
}
Array.prototype.some (EcmaScript 5):
var flagExistsLoop = tempListArray.some(function(item) {
return item.id == Id;
});
Note it may be slower than the other ones because it calls a function at each step.
for...of loop (EcmaScript 6):
for (var item of tempListArray) {
if (item.id == Id) {
flagExistsLoop = 1;
break;
}
}
Depending on your scenario, you may be able to use Array.indexOf() which will return -1 if the item is not present.
Granted it is probably iterating behind the scenes, but the code is much cleaner. Also note how object comparisons are done in javascript, where two objects are not equal even though their values may be equal. See below:
var tempListArray = [{"id":"12","value":false},{"id":"10","value":false},{"id":"9","value":false},{"id":"8","value":false}];
var check1 = tempListArray[2];
var check2 = {"id":"9","value":false};
doCheck(tempListArray, check1);
doCheck(tempListArray, check2);
function doCheck(array, item) {
var index = array.indexOf(item);
if (index === -1)
document.write("not in array<br/>");
else
document.write("exists at index " + index + "<br/>");
}
try to use php.js it may help while you can use same php function names and it has some useful functionalities
There is no way without iterating through the elements (that would be magic).
But, you could consider using an object instead of an array. The object would use the (presumably unique) id value as the key, and the value could have the same structure you have now (or without the redundant id property). This way, you can efficiently determine if the id already exists.
There is a possible cheat for limited cases :) and it is magic...cough cough (math)
imagine you have 3 elements:
1
2
3
and you want to know if one of these is in an array without iterating it...
we could make a number that contains a numerical flavor of the array. we do this by assigning prime numbers to the elements:
1 - 2
2 - 3
3 - 5
the array so when we add item 2 we check that the array doesn't already contain the prime associated to that item by checking (if Flavor!=0 && (Flavor%3)!=0) then adding the prime Flavor*=3;
now we can tell that the second element is in the array by looking at the number.
if Flavor!=0 && (Flavor%3)==0 // its There!
Of course this is limited to the numerical representation that can be handled by the computer. and for small array sizes (1-3 elements) it might still be faster to scan. but it's just one idea.
but the basis is pretty sound. However, this method becomes unusable if you cannot correlate elements one to one with a set of primes. You'll want to have the primes calculated in advance. and verify that the product of those is less numerical max numerical representation. (also be careful with floating-point. because they might not be able to represent the number at the higher values due to the gaps between representable values.) You probably have the best luck with an unsigned integer type.
This method will probably be too limiting. And there is something else you can do to possibly speed up your system if you don't want to iterate the entire array.
Use different structures:
dictionaries/maps/trees etc.
if your attached to the array another method can be a bloom filter. This will let you know if an element is not in your set, which can be just as useful.

Passing Variable length array to function Node JS

Is there a way to call an addon function with a variable length. I take the user input into a variable that looks like
Uinput = [5,3,2];
Now i want to call my addon based on these numbers so it would be
addon.myaddon(5,3,2);
I also want to extend this to n inputs so if my variable of user inputs becomes
Uinput = [5,3,2,6,...,n];
then the addon will be called like
addon.myaddon(5,3,2,6,...,n);
addon.myaddon(Uinput) // will not seperate the inputs by commas are they are in the array variable, it treats the whole array as the input
This seems simple enough but it is giving me a bit of trouble. Any tips ?
Take a look at Function.prototype.apply
Uinput = [5,3,2,...,7]; // the last number in the array is in position 'n'
addon.myaddon.apply(null, Uinput);
This is equivalent to calling:
addon.myaddon(Uinput[0], Uinput[1], Uinput[2], ... , Uinput[n]);
Real example using Math.max:
// Basic example
Math.max(1,6,3,8,4,7,3); // returns 8
// Example with any amount of arguments in an array
var mySet = [1,6,3,8,4,7,3];
Math.max.apply(null, mySet); // returns 8

How do I use #DbLookup results to populate a Readers field in xpages?

db = new Array("myserver", "myfolder\\mydb.nsf")
dir = getComponent("Dir").value;
div = getComponent("Div").value;
lu = #DbLookup(db, "ManagerAccess", dir + "PP" + div, "DTManagers");
var a = [];
a.push(lu);
var item:NotesItem = docBackEnd.replaceItemValue('FormReaders', #Unique(a));
item.setReaders(true);
That code is on the querySaveDocument ssjs. The result I get from the #DbLookup (when I put in a computed field) look like this:
Pedro Martinez,Manny Ramirez,David Ortiz,Terry Francona
I tried doing an #Explode(#Implode) thing on it, but it doesn't seem to work.
The error I get in the browser just tells me that the replaceItemValue line is broken.
To test it, I pushed several strings one at a time, and it worked correctly populating my FormReaders field with the multiple entries.
What am I doing wrong?
I see several problems here:
A. In cases as described by you #Dblookup in fact would return an array. If you push an array into a plain computedField control it will exactly look as that you wrote:
value1, value2, ..., valueN
A computedField doesn't know anything about multiple values etc, it just can display strings, or data that can be converted to strings.
If you want to test the return value you could try to return something like lu[0]; you then should receive the array's 1st element, or a runtime error, if lu is NOT an array. Or you could ask for the array's size using lu.length. That returns the number of array elements, or the number of characters if it's just a plain string.
B. your code contains these two lines:
var a = [];
a.push(lu);
By that you create an empty array, then push lu[] to the first element of a[]. The result is something like this:
a[0] = [value1, value2, ..., valueN],
i.e. a is an array where the first element contains another array. Since you don't want that, just use #Unique(lu) in your replaceItemValue-method.
C. I don't see why replaceItemValue would throw an error here, apart from what I wrote in topic B. Give it a try by writing lu directly to the item (first without #Unique). That should work.
D. for completeness: in the first line you used "new Array". A much better way to define your db parameters is
var db = ["myserver", "myfolder/mydb.nsf"];
(see Tim Tripcony's comment in your recent question, or see his blog entry at http://www.timtripcony.com/blog.nsf/d6plinks/TTRY-9AN5ZK)

JavaScript: memory/efficiency of associative arrays?

I am building a tree-like data structure out of associative arrays. Each key is 1-2 characters. Keys are unique to their respective level. There will be no more than 40 keys on the root level and no more than 5 keys on each subsequent levels of the tree. It might look something like this:
{a:{b:null,c:null},de:{f:{g:null}},h:null,i:null,j:null,k:null}
Initially, I thought that creating so many objects with so few keys (on average, < 3) would be inefficient and memory intensive. In that case, I would implement my own hash table like so:
//Suppose keys is a multi-dimensional array [[key,data],...]
var hash = function(keys){
var max = keys.length*3, tbl = [];
//Get key hash value
var code = function(key){
return (key.charCodeAt(0)*31)%max;
}
//Get key values
this.get(key){
//2 character keys actually have a separate hash generation algorithm...
//we'll ignore them for now
var map = code(key), i=map;
//Find the key value
while(true){
if (typeof tbl[i] == 'undefined') return false;
if (code(tbl[i][0]) == map && tbl[i][0] == key) return tbl[i][1];
else i = (i+1)%max;
}
}
//Instantiate the class
for (var i=0; i<keys.length; i++){
var index = code(keys[i][0]);
while(typeof tbl[index] != 'undefined')
index = (index+1)%max;
tbl[index] = keys[i];
}
}
Then, I read somewhere that JavaScript's arrays are sometimes implemented as associative arrays when sparsely filled, which could defeat the purpose of making my own hash structure. But I'm not sure. So, which would be more efficient, in terms of memory and speed?
Read this article: http://mrale.ph/blog/2011/11/05/the-trap-of-the-performance-sweet-spot.html
Basically due to the dynamic nature of JavaScript, your data structures will not be very efficient. If you do need very efficient data structures, you should try using the new Typed Arrays introduced recently.
If you aren't into theoretical results, Resig has done real word performance testing on different types of trees looking at data size and performance parsing and processing: http://ejohn.org/blog/javascript-trie-performance-analysis/
Your solution, if I understand it correctly, will definitely perform worse. You express a concern with this:
[...] creating so many objects with so few keys (on average, < 3) [...]
but your solution is doing the same thing. Every one of your nested hashes will still be an object with a small number of keys, only now some of its keys are a closure named get (which will have higher memory requirements, since it implicitly closes over variables such as tbl and code, where code is another closure . . .).

Categories