I'm porting some JavaScript to Java and I'm having a hard time understanding two lines of the following piece of code:
var blocks=[];
for (var z=0; z<size; z++) {
var slice=blocks[z]=[]; //Those are the lines I don't understand.
for (var x=0; x<size; x++) {
var row=slice[x]=[]; //Those are the lines I don't understand.
for (var y=0; y<size; y++) {
row[y]=isFull(x,y,z);
}
}
}
The first line is declaring "slice", then it assigns "blocks[z]", and then again it assigns an empty array.
As I'm writing this it came to my head that maybe is for clearing any previous info before assigning new data, but I'm not sure.
Actually an empty array is assigned to blocks[z], and the value of blocks[z] (the empty array) is then assigned to slice.
Basically it's just a short way of assigning a value to two (or more) variables
yes and no, it would clear previous data, but that's what var is doing anyways.
The important part is that it assigns an array so that the following lines don't crash
blocks =[]; // blocks is an array of zero length 'filled' with NULL values;
var slice = blocks[z]; // slize would be the same as blocks[z] so it'd be NULL
blocks[z] = []; // blocks[z] is now an zero length array filled with NULL values.
All assignment code is executed from right to left so it first assigns an array to blocks[z] and assigns that same array to var slice
and so forth
x = y = z;
is exactly equivalent to:
y = z;
x = y;
in that order.
Related
I have two arrays of values. I want to use the elements of one array to be the argument of an indexOf function. But I get a -1 (meaning value not found) even when I know the value exists in the array.
I have tested this by hard coding the value in the argument of indexOf so I know in this case that my problem is with cur_data variable. When I hard code the cur_data[x] with 'xyz' the indexOf returns correct index however when I use the array value [xyz] it returns -1.
What am I doing wrong?
function iterateSheets() {
var price_data = SpreadsheetApp.openById('1Nttb7XqUlZwGtmwbcRc3QkY3f2rxx7XdsdEU3cK4K4').getSheetByName('price').getRange("A2:A353").getValues()
var price_data2 = price_data.map(function(r) {
return r[0];
});
var test = new Array(30)
var ts = SpreadsheetApp.openById('18qFvVMVEE1k5DWUYaSezKeobcLr8I4oAmHLUpd_X99k');
var allShts = ts.getSheets();
for (var i = 0; i < 1; i++) //allShts.length //need to add in code to make sure tab is one of the fcst tabs
{
var cur_data = allShts[i].getRange("B8").getValues()
if (allShts[i].getName() == "July" || allShts[i].getName() ==
"Aug" || allShts[i].getName() == "Sept") {
for (var x = 0; x < 1; x++) {
Logger.log(cur_data[x])
Logger.log(price_data2.indexOf(cur_data[x]));
}
}
}
}
2D Array of values
getValues() method returns a two-dimensional Array of values from the Range that should be accessed via the values[row][column] schema. The for loop only increments the first dimension, that is, rows, and never accesses the value via column reference. Thus, you end up passing an Array instance to the indexOf() method.
Modification
You can add a second for loop to iterate over each of the elements of the Array of values, plus modify the first loop to make it more flexible just in case you ever need to loop over multiple rows:
for (var x = 0; x < cur_data.length; x++) {
for (var y = 0; y < cur_data[x].length; y++) {
Logger.log(cur_data[x][y])
Logger.log(price_data2.indexOf(cur_data[x][y]));
}
}
Comparison
indexOf() method performs search via the strict equality comparison and here is where the fun part starts. As Array instances are also Objects, meaning the same rules of comparison that apply to objects apply to them. This means that no two objects are equal (take a look at the comparison result table).
Useful links
getValues() reference;
indexOf() MDN reference;
Equality comparisons guide;
I have an array of objects
x = [{id:null},{id:null},{id:null},{id:null}];
Lets say that the values for the array changed
x = [{id:1},{id:3},{id:8},{id:12}];
And i wanted to revert the values to all null,which method will be faster for performance
A) Reconstructing the array again
x=[];
for (var i=0; i<5; i++) {
var obj = {};
obj.id = null;
x.push(obj);
}
B) Resetting the values
for (var i in x) {
x.id = null;
}
Unless you have thousands of elements, you will never notice a difference in performances.
However the second solution is more clear than the first one.
Alternatively, to make it clear x is an array:
for (var i = 0; i < x.length; ++i) {
x[i].id = null;
}
Your B will just add property id to your array and set it's value to 'null'. On top of that, you should not use for in on arrays.
Fastest way would probably be:
var i = x.length;
while(i--){
x[i].id = null;
}
But you wouldn't see the difference unless your array has thousands of elements, and probably shouldn't even try to optimize it for the performance, before you're sure that you need to. In most use cases readability of the code will be much more important than a few fragments of a second that you could gain.
I have a situation where I may be setting an array cell of a high index without setting any of the cells before it.
>>> var arr = [];
undefined
>>> arr[5] = 'value';
"filled"
>>> arr
[undefined, undefined, undefined, undefined, undefined, "filled"]
How is such an array stored in memory? Is there space allocated for each undefined value?
In my actual project, I may be using very large indices. For example, I may set cells 500-800 and 900-1000. I can't use a hash because I need to loop through these non-empty cells and be aware of their index. I want to know if fragmenting the array like this will use up a ton of memory for the empty cells.
Strapping onto aefxx's answer, you can still iterate:
var obj = {500: "foo", 10923: "bar"};
var max = 0;
for (var key in obj)
max=key>max?key:(max||key); // get max key
for (var i=0; i<=max; i++)
console.log(obj[i]); // output even the undefined
As Phrogz commented, it doesn't allocate for undeclared elements of the array. I'm not certain if that's the case if you explicitly set the element value to undefined (e.g. arr[somenum] = undefined;)
I can't use a hash because I need to loop through these non-empty cells and be aware of their index.
What's wrong with the for (x in ...) language construct?
EDITED to accomodate vol7ron's comment:
var x = {2: "foo", 999: "bar"};
for ( var n in x ) {
if ( x.hasOwnProperty(n) ) {
console.log(n);
console.log(x[n]);
}
}
You should probably simply store the max index in a variable and the access your map like this :
for (var i=0; i<=maxIndex; i++) {
console.log(myMap[i]);
}
Then you'll have the (relative) compacity of the map and the ability to loop through unsetted indexes.
In the following code sample i get a strange behavior
var data = ['xxx', 'yyy'];
for (var i in data)
{
var a = i;
var b = data[i];
}
The two first iterations works just fine. I get index "0" and "1" in i, but then it loops one extra time and now the i is "sum". Is this by design or what is this extra iteration used for? The result in my case is always empty and it messes up my code. Is there a way to not do his extra loop?
BR
Andreas
It looks like you (or some other code you've included) have added extra properties onto the Array prototype. What you should be doing is checking to see whether the object you're iterating over actually has that property on itself, not on its prototype:
for (i in data) {
if (data.hasOwnProperty(i)) {
a = i;
b = data[i];
}
}
That said, you should never use for .. in on arrays. Use a regular for loop.
See here for more information: http://yuiblog.com/blog/2006/09/26/for-in-intrigue/
You are looping through an Array, not through an Object. For arrays it's better to use:
for (var i=0; i<data.length; i=i+1){
/* ... */
}
In your loop every property of the Array object is taken into account. That makes the for ... in loop for array less predictable. In your case it looks like sum is a property (method) that's added to Array.prototype elsewhere in your code.
There are more ways to loop through arrays. See for example this SO-question, or this one
Just for fun, a more esoteric way to loop an array:
Array.prototype.loop = function(fn){
var t = this;
return (function loop(fn,i){
return i ? loop(fn,i-1).concat(fn(t[i-1])) : [];
}(fn,t.length));
}
//e.g.
//add 1 to every value
var a = [1,2,3,4,5].loop(function(val){return val+1;});
alert(a); //=> [2,3,4,5,6]
//show every value in console
var b = [1,2,3,4,5].loop(function(val){return console.log(val), val;});
Here's a way to safely iterate.
var data = ['xxx', 'yyy'];
for (var i = 0; i < data.length; i++)
{
var a = i;
var b = data[i];
}
What you are getting is an method coming from extending the Array object, I guess you are using some library where is something like
Array.prototype.sum = function () {...};
Perhaps setting data like this would work better: var data = {0:'xxx', 1:'yyy'};
First of all data is an object. Try to add console.log(a); and console.log(b); inside your loop and you'll see.
Imagine the following situation:
var array = new Array ( [0,0,0,0], [0,0,1,0], [0,0,0,0] );
var x = 0; var y = 0;
if(array[y][x]) {
// x and y can be any integer
// code should execute only for array[1][2]
}
When x and y refer to an item in the array that exists, everything is fine. Otherwise, the script terminates. Obviously this is not the behaviour I want - is it possible to reference Javascript multidimensional arrays safely?
You need to check that the referenced property exists at each level of the array:
if(array[y] && array[y][x]) {
// x and y can be any integer
// code should execute only for array[2][1]
}
You can use the in keyword to check whether there is a y-th element of the array and whether that element has a x-th element as preliminary checks:
if (y in array && x in array[y] && array[y][x]) {...
Javascript arrays aren't so much multidimensional as they are compound/jagged. You can also use Array.length, but that relies on the object being an array, which is part of what we're checking, so it complicates the check.
A bit more verbose than the other answers:
var array = [ [0,0,0,0], [0,0,1,0], [0,0,0,0] ];
var x = 0; var y = 0;
if(array.hasOwnProperty(y) && array[y].hasOwnProperty(x) && array[y][x] !== 0) {
// x and y can be any integer
// code should execute only for array[2][1]
}
...but this one is impervious to additions to Array.prototype.
Also, explicitly testing for equality with zero makes it more readable, IMHO. (Compensating for the reduced readability of the preceding conditions... :-P)