Javascript: Passing Address of Array Element into Function - javascript

In FORTRAN and C++, the address of a specific array element can be passed into a function. For example, in the main routine, WA1 is a work array of size 25 and offset is an integer variable that indicates the offset from the 0-index. Say offset is presently 6.
The declaration of the sub-routine might look like the following:
void Array_Manip1(double* WorkArray1){
. . .
When the sub-routine is called in the main program, the call might look like this:
Array_Manip1(&WA1[offset]);
By doing this, I can index WorkArray1 within the sub-routine starting at the 0-index, but knowing it is actually WA1[6].
e.g. -
for (int i = 0; i < 19; ++i)
WorkArray1[i] = whatever computation is required.
To do this in Javascript, I suppose the full array could be passed in to the sub-routine, plus one more variable to hold the offset. And then within the sub-routine, the offset would have to be added to the array index value.
e. g. -
for (int i = 0; i < 19; ++i){
WorkArray1[offset + i] = whatever computation is required.
But now I am passing one more variable into the sub-routine, and have to add the offset to the array index each time through the loop.
Is there a better way to do this in Javascript?
Is there a way to imitate C++'s ability to pass the address of a specific array element into a function?

The cleanest way would be to splice the array and pass in a subarray from the current index on. That way you still have one reference, and everything stays clean.
But no, arrays in most higher level languages do not allow you to reference a single element and then get back to the array. It is dangerous for a number of reasons on those kinds of languages where the underlying data may not even be stored contiguously. JavaScript is no exception, and you can pass in an array and an index, or a subarray, but you can't pass in a reference to an element in the array and get back to the array after passing it in.

Tim's answer is correct. I just want to add something about the C-like typed arrays: they can be created as a view into an ArrayBuffer, in which case you could create a new view of the same buffer as the larger array but starting at an offset, and pass that, without duplicating the underlying data. Closest you can get to your pointers.

You can sort of do what you want. And in fact, sometimes javascript can only do what you want. It all depends on what data the array contains.
In Javascript, the content of a variable may either be a value or a reference (pointer but without pointer arithmetic). But you have no choice in the matter. Numbers and strings are always values (there are exceptions but none of them apply when passing as function arguments) and everything else are always references.
So to get the behavior you want, simply use an object or array as your value holder instead of a string or number:
var ref_array = [ {value:1}, {value:2}, {value:3} ];
function increment (v_obj) {
v_obj.value ++;
}
var ref = ref_array[1];
increment(ref);
// ref_array will now contain: [{value:1},{value:3},{value:3}]
It's not that simple though. While the object appears to be passed by reference, the reference is however copied when the function is called. What this means is that ref and ref_array[1] and v_obj are three separate variables that point to the same thing.
For example, this wouldn't work:
function replace (obj1, obj2) {
obj1 = obj2;
}
replace(ref_array[1], {value:9});
// ref_array is still: [{value:1},{value:3},{value:3}]
That's because, while obj1 in the function above points to the same object as ref_array[1], it is not really a pointer to ref_array[1] but a separate variable. In C, this would be something like obj1 = &ref_array[1]. So passing an argument passes a copy of the pointer but not the pointer itself.

Related

What is the best way to itterate over key value pairs nested in an index using javascript?

I am trying to sort sets of associated key value pairs. They look like this:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
But organized into labeled subsets of preferably a string or perhaps an index if necessary.
The data-set is a vote-per-use table of most used english words being parsed into pages.
I will be appending them as text to other html elements due to the constraints my use case, makes it a bit tricky, however, for an example I could work with a simple console.log of the page value followed by the console.log of every word value stored within that page. I need the order preserved. so probably indexed. I will also need to be able to sort each page by the votes value, but I think I can figure the rest out for that.
I have found tutorials on how to search through key-value pairs, but I cannot find how to do all of the following with one solution:
A: access the value of word
B: maintain the order of the data-set, allowing me to append them to the matching html element
C: allows me the opportunity to change which set of elements I am appending to when i have finished looping through a single member of the parent index (the one recording the page)
I imagine it is some combination of for/of and for/in, but I'm getting a headache. Please help?
addl info:
function would run at app startup or when the dataset being examined is changed.
function would take a large dataset filled with around 200 page number values, each with 60+ sets of data like the one listed above, the contents of a single page index for example:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abandoned","votes":1289,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abc","votes":5449,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aberdeen","votes":641,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abilities","votes":2210,"userMade":"FALSE","limiter":"FALSE"},
{"word":"ability","votes":7838,"userMade":"FALSE","limiter":"FALSE"},
{"word":"able","votes":8649,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aboriginal","votes":1837,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abortion","votes":3232,"userMade":"FALSE","limiter":"FALSE"},
{"word":"about","votes":9295,"userMade":"FALSE","limiter":"FALSE"},
{"word":"above","votes":8818,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abraham","votes":867,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abroad","votes":4969,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abs","votes":2415,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absence","votes":4934,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absent","votes":2937,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolute","votes":5251,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolutely","votes":5936,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absorption","votes":285,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstract","votes":7946,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstracts","votes":1907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abuse","votes":7238,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academic","votes":7917,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academics","votes":1706,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academy","votes":6755,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acc","votes":6469,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accent","votes":1020,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accept","votes":7547,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptable","votes":4907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptance","votes":7273,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepted","votes":7684,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepting","votes":1789,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepts","votes":1535,"userMade":"FALSE","limiter":"FALSE"},
{"word":"access","votes":9031,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessed","votes":2932,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessibility","votes":5702,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessible","votes":5662,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessing","votes":2096,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessories","votes":8875,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessory","votes":5661,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accident","votes":5664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accidents","votes":2991,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodate","votes":1807,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodation","votes":8059,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodations","votes":3885,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanied","votes":2532,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanying","votes":664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplish","votes":1070,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplished","votes":2419,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordance","votes":6434,"userMade":"FALSE","limiter":"FALSE"},
{"word":"according","votes":8282,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordingly","votes":3003,"userMade":"FALSE","limiter":"FALSE"},
{"word":"account","votes":8996,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accountability","votes":3029,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounting","votes":7459,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounts","votes":7507,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accreditation","votes":1605,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accredited","votes":3027,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accuracy","votes":6779,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurate","votes":6427,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurately","votes":1493,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accused","votes":2853,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acdbentity","votes":1389,"userMade":"FALSE","limiter":"FALSE"},
and the output would ultimately append the value paired with each word to a specific button through iteration, but also sorted by the page value.
each page is a set of buttons in a 3d object that looks like this:
the text is appended to each button which in turn is a 3d object embeded in an html object using aframe. I can make the appending code.
You can use Object.entries() to get the key value pairs of an object.
var words = [
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"}
];
words.forEach((wordEntry) => {
var keyValuePairs = Object.entries(wordEntry);
keyValuePairs.forEach((kv) => {
console.log(`key: ${kv[0]} value: ${kv[1]}`);
});
});
my latest attempt looks like this:
for (let p=1; p<129; p++){
for (let b=1; b<68; b++){
let pTpl = (p).toLocaleString(undefined, {minimumIntegerDigits: 3});
let bDbl = (b).toLocaleString(undefined, {minimumIntegerDigits: 2});
var `#fCont${pTpl}${bDbl}` = document.createElement('a-text');
`fCont${pTpl}${bDbl}`.setAttribute('value', 'engWordLib[p,b,0]');
`fCont${pTpl}${bDbl}`.setAttribute('votes', 'engWordLib[p,b,1]');
`fCont${pTpl}${bDbl}`.setAttribute('userMade', 'engWordLib[p,b,2]');
`fCont${pTpl}${bDbl}`.setAttribute('limiter', 'engWordLib[p,b,3]');
`fCont${pTpl}${bDbl}`.setAttribute('visible', 'false');
`fBtn${bDbl}`.appendChild(`#fCont${pTpl}${bDbl}`)
}
}
please note that I havent checked this for errors. I still think this code is to WET and I would prefer the key names for the properties be preserved in the datastructure rather than tacked on when it's appended to the page. I guess I could add a dimension to the array.... seems kind of messy when an object property value has the key value pairs right in it. cant get the iteration of objects in an array down though.... Will continue to persue a cleaner method.

what is use of adding length property to objects in javascript?

Array do support length property as well as string does, but objects don't inherently have a length property.
in case we add a length properly as below.
{"a":0,"b":0,length:2}
what is the use case scenario for above code
An object doesn't have a length, per se. It depends on what this length represents.
For example, in the code you posted, it's not immediately obvious why the length is 4, but it might make sense in the context of what that object actually represents.
Here are both methods of getting the length.
You'll notice if you keep track of your own length the display code is a bit shorter but you need a whole function to add a new key, you'd even need another function to remove them.
object.keys changes the keys into an array which we can get the length from this, of course, take a few milliseconds more as it has to do the convert.
I generally run with the assumption a computer is going to make fewer mistakes than me so, if I can, I should load as much work as possible onto it.
// initial set up
let obj1 = {"a":0,"b":0};
let obj2 = {"a":0,"b":0,length:2};
// initial lengths
console.log("obj1: "+Object.keys(obj1).length);
console.log("obj2: "+obj2.length);
// adding standard way
obj1["c"] = 0;
// adding to accomidate with length
function addObj2(key, value) {
obj2[key] = value;
obj2.length++;
}
addObj2("c",0);
console.log("--");
// new lengths
console.log("obj1: "+Object.keys(obj1).length);
console.log("obj2: "+obj2.length);
I hope this makes sense.

Can I make a "Virtual Array" in JavaScript?

I'm calling a JavaScript function that wants an array of things to display. It displays a count, and displays the items one by one. Everything works when I pass it a normal JavaScript array.
But I have too many items to hold in memory at once. What I'd like to do, is pass it an object with the same interface as an array, and have my method(s) be called when the function tries to access the data. And in fact, if I pass the following:
var featureArray = {length: count, 0: func(0)};
then the count is displayed, and the first item is correctly displayed. But I don't want to assign all the entries, or I'll run out of memory. And the function currently crashes when the user tries to display the second item. I want to know when item 1 is accessed, and return func(1) for item 1, and func(2) for item 2, etc. (i.e., delaying the creation of the item until it is requested).
Is this possible in JavaScript?
If I understand correctly, this would help:
var object = {length: count, data: function (whatever) {
// create your item
}};
Then, instead of doing array[1], array[2], et cetera, you'd do object.data(1), object.data(2), and so on.
Since there seems to be a constraint that the data must be accessed using array indexing via normal array indexing arr[index] and that can't be changed, then the answer is that NO, you can't override array indexing in Javascript to change how it works and make some sort of virtual array that only fetches data upon demand. It was proposed for ECMAScript 4 and rejected as a feature.
See these two other posts for other discussion/confirmation:
How would you overload the [] operator in Javascript
In javascript, can I override the brackets to access characters in a string?
The usual way to solve this problem would be to switch to using a method such as .get(n) to request the data and then the implementor of .get() can virtualize however much they want.
P.S. Others indicate that you could use a Proxy object for this in Firefox (not supported in other browsers as far as I know), but I'm not personally familiar with Proxy objects as it's use seems rather limited to code that only targets Firefox right now.
Yes, generating items on the go is possible. You will want to have a look at Lazy.js, a library for producing lazily computed/loaded sequences.
However, you will need to change your function that accepts this sequence, it will need to be consumed differently than a plain array.
If you really need to fake an array interface, you'd use Proxies. Unfortunately, it is only a harmony draft and currently only supported in Firefox' Javascript 1.8.5.
Assuming that the array is only accessed in an iteration, i.e. starting with index 0, you might be able to do some crazy things with getters:
var featureArray = (function(func) {
var arr = {length: 0};
function makeGetter(i) {
arr.length = i+1;
Object.defineProperty(arr, i, {
get: function() {
var val = func(i);
Object.defineProperty(arr, i, {value:val});
makeGetter(i+1);
return val;
},
configurable: true,
enumerable: true
});
}
makeGetter(0);
return arr;
}(func));
However, I'd recommend to avoid that and rather switch the library that is expecting the array. This solution is very errorprone if anything else is done with the "array" but accessing its indices in order.
Thank you to everyone who has commented and answered my original question - it seems that this is not (currently) supported by JavaScript.
I was able to get around this limitation, and still do what I wanted. It uses an aspect of the program that I did not mention in my original question (I was trying to simplify the question), so it is understandable that other's couldn't recommend this. That is, it doesn't technically answer my original question, but I'm sharing it in case others find it useful.
It turns out that one member of the object in each array element is a callback function. That is (using the terminology from my original question), func(n) is returning an object, which contains a function in one member, which is called by the method being passed the data. Since this callback function knows the index it is associated with (at least, when being created by func(n)), it can add the next item in the array (or at least ensure that it is already there) when it is called. A more complicated solution might go a few ahead, and/or behind, and/or could cleanup items not near the current index to free memory. This all assumes that the items will be accessed consecutively (which is the case in my program).
E.g.,
1) Create a variable that will stay in scope (e.g., a global variable).
2) Call the function with an object like I gave as an example in my original question:
var featureArray = {length: count, 0: func(0)};
3) func() can be something like:
function func(r) {
return {
f : function() {featureArray[r + 1] = func(r + 1); DoOtherStuff(r); }
}
}
Assuming that f() is the member with the function that will be called by the external function.

What is a good way to create a JavaScript array with big indices?

I'm making a web app where a user gets data from PHP, and the data consists of MySQL rows, so I want to save the used ones in a global variable, something like a buffer, to prevent extra AJAX requests.
I'm doing this right now :
window.ray = []; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
but when the id is big, say 10 for now, window.ray becomes this :
,,,,,,,,42
so it contains 9 unnecessary spots. Or does it? Is it only visible when I'm doing console.log(window.ray);
If this is inefficient, I want to find a way like PHP, where I can assign only indices that I want, like :
$array['420'] = "abc";
$array['999'] = "xyz";
Is my current way as efficient as PHP, or does it actually contain unnecessary memory spots?
Thanks for any help !
Use an object instead of an array. The object will let you use the id as the key and be more efficient for non-sequential id values.
window.ray = {}; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
You can then access any element by the id:
var text = window.ray[myId];
If you are assigning values directly by property name, then it doesn't make any difference in terms of performance whether you use an Array or an Object. The property names of Arrays are strings, just like Objects.
In the following:
var a = [];
a[1000] = 'foo';
then a is (a reference to) an array with length 1,001 (always at least one greater than the highest index) but it only has one numeric member, the one called '1000', there aren't 1,000 other empty members, e.g.:
a.hasOwnProperty['999']; // false
Arrays are just Objects with a special, self–adjusting length property and some mostly generic methods that can be applied to any suitable object.
One feature of sparse arrays (i.e. where the numeric properties from 0 to length aren't contiguous) is that a for loop will loop over every value, including the missing ones. That can be avoided and significant performance gains realised by using a for..in loop and using a hasOwnProperty test, just like an Object.
But if you aren't going to use any of the special features of an Array, you might as well just use an Object as suggested by jfriend00.

filling a multidimensional array within "for" loop (javascript)

It seems like JavaScript somehow tries to optimize code, so if we want to fill a multidimensional array (largeArr) with changing values of one-dimensional array (smallArr) within a loop and use this code:
largeArr = []
smallArr = []
for (i=0; i<2; i++)
{
smallArr[0]=i
smallArr[1]=2*i
largeArr[i]=smallArr
}
we get an unexpected result: largeArr=[[1,2],[1,2]] (must be [[0,0],[1,2]]). So, Javascript calculates smallArr values in the first place, and only then fills largeArr.
To get the right result we must declare smallArr in the loop:
largeArr = []
for (i=0; i<2; i++)
{
smallArr = []
smallArr[0]=i
smallArr[1]=2*i
largeArr[i]=smallArr
}
and then it works as expected (largeArr=[[0,0],[1,2]]).
Why does it behave this way?
Because Pointers, that's why. Javascript takes after Java, and C, in this (and only this) way. When you do the assignment
largeArr[i] = smallArr
you're assigning a pointer. A breakdown of pointers:
In C, (and to a lesser extent, Java and Javascript) you don't have a basic array type - instead, an array points to a space in memory, and you can fill that space with whatever information you want (or rather, you've declared). The way a pointer exists in memory? A four (or eight, or two, depending on your system) byte memory address, which tells the compiler/parser where to get the appropriate in formation. So, when you do that assignment there, you're telling it: "Hey, set largeArr[i] equal to the memory address of smallArr." Thus, when you make changes to smallArr, it's reflected every time you dereference the array - because it's actually the same array. But when you do:
smallArr = []
inside the loop, you're saying, "make a new array, and set smallArr equal to the address of that array." That way, the arrays stay separate.
With the line largeArr[i]=smallArr, you set the i property to a reference to the smallArr. You do not copy it. In the end, all properties of the largeArr will point to the same one smallArr, where you have overwritten the values each time.
By initializing the smallArr each loop turn, you create new objects; so each property of largeArr will point to a different array. Btw, it is an assignment, not a declaration - you would (and should) declare the variables as local (to the function) with a var statement.
In the last for iteration
smallArr[0]=i
smallArr[1]=2*i
(where i=1) the above code is transformed into :
smallArr[0]=1
smallArr[1]=2
And your big array is nothing than this :
[smallArr, smallArr]
which leads to the unexpected result :
[[1, 2], [1, 2]]
In javascript objects are copyed by reference (a kind of c style pointer).
In order to have the desired result, you must copy the array by value, or assign a different array in each loop :
var largeArr = [];
for (i=0; i<2; i++)
largeArr[i] = [[i, 2*i]];
When you assign an array reference as you have above, you're not assigning the values of that array, but just a reference to the array.
Think of it as a pointer. largeArr[0] and largeArr[1] are pointing to smallArr, and the loop iterations are simply changing the contents of smallArr. The thing to which largeArr is being "pointed" is not changing.

Categories

Resources