I have an object,
obj = {};
now I am adding items into this object as,
obj[element] = /*something*/
now if I want to access this object for key = element as,
obj[element];
what would be time complexity of this operation.
And please dont suggest using of Array instead of Object, I know array has constant time look up because I am adding elements at random numbers (using them as index), so if Ii use array, I will have a sparse array and that would be inefficient in terms of memory.
It is minimal enough for you to not worry about it. Objects are a core part of javascript, and micro-optimization is bad.
You're much better off writing understandable code (whether it's with objects or what-not) than writing code that saves you 0.000000000001 seconds.
Just you need to know: Array is an Object too in JavaScript.
Also to check speed of any operation you can do something like:
var obj = {}, element = "test";
obj[element] = 333333;
var time1 = new Date().getTime(); // start timestamp
for (var i=0; i<1000; i++)
{
// here can be any code for measurement
var a = obj[element];
}
var time2 = new Date().getTime(); // end timestamp
var result = (time2 - time1) / 1000; // divide all time to number of iterations
alert(result + " ms");
Related
In Google Earth Engine Developer's Guide, there is a recommendation to avoid for() loops. They recommend to use map() function as this example:
// to avoid
var clientList = [];
for(var i = 0; i < 8; i++) {
clientList.push(i + 1);
}
print(clientList);
// to use
var serverList = ee.List.sequence(0, 7);
serverList = serverList.map(function(n) {
return ee.Number(n).add(1);
});
print(serverList);
I'm trying to select MODIS scenes from each month/year prior to compute VCI. So, the approach I'd take is with a double loop:
modis = ee.ImageCollection("MODIS/MYD13A1");
var modis_list = [];
for(var i = 1; i <13; i++) {
for(var j = 2000; j <2018; j++){
modis_list.push(modis.filter(ee.Filter.calendarRange(i, i, 'month'))
.filter(ee.Filter.calendarRange(j, j, 'year')));
}
}
print(modis_list);
Is there a way to replicate a double loop like this with map() function to reach a server-side approach?
The easy way to do this is with a single map over the "months" you care about.
// Collect images for each month, starting from 2000-01-01.
var months = ee.List.sequence(0, 18*12).map(function(n) {
var start = ee.Date('2000-01-01').advance(n, 'month')
var end = start.advance(1, 'month')
return ee.ImageCollection("MODIS/MYD13A1").filterDate(start, end)
})
print(months.get(95))
This will return a list of ImageCollections. Most months will have only 1 image, since MYD13A1 contains 16-day images, but some will have two. Month 95 is Jan of 2008 and has two.
Alternatively, you could join the collection with a collection of dates, but this is simpler.
And you should prefer filterDate over calendarRange when possible, as it's optimized.
Assuming that you are just trying to understand GEE's map() function, and how would be the equivalent of a normal js for loop, the code would be:
var map_m = function(i) {
i = ee.Number(i)
var years = ee.List.sequence(2000, 2017)
var filtered_col = years.map(function(j) {
var filtered = modis.filter(ee.Filter.calendarRange(i, i, 'month'))
.filter(ee.Filter.calendarRange(j, j, 'year'))
return filtered
})
return filtered_col
}
var months = ee.List.sequence(1, 12)
var modis_list2 = months.map(map_m).flatten()
This code replicates a normal for loop. First, it goes item by item of the years list, and then item by item of the months list, and then, once you have year and month, filter the collection and add it to a list (map does that automatically). As you use 2 map functions (one over years and the other over months), you get a list of lists, so to get a list of ImageCollection use the flatten() function. Somehow the printed objects are a bit different, but I am sure the result is the same.
Let me start by saying I know nothing about Google Earth Engine and my info is from functional programming knowledge.
map is unique in that it doesn't generate the things it loops over. You start with a list and map iterates over each item in that list and transforms it. If you don't have that list then map isn't a great fit.
It looks like you are creating a list with each month/year combo represented. I would break this into a few steps. Build the month and year lists, build the list that represents cartesian product of the 2 lists then transform to the ee objects.
var range = (from, to) => new Array(end-start+1).fill(0).map((_,i)=>i+from)
var cartesianProduct = (a, b) => // not gonna do this here but it returns pairs [ [ a[1], b[1] ], ... ]
var getEE = ([month, year]) => modis
.filter(ee.Filter.calendarRange(month, month, 'month'))
.filter(ee.Filter.calendarRange(year, year, 'year'));
var months = range(1,12);
var years = range(2000, 2017);
var data = cartesianProduct(months, years)
.map(getEE)
There are likely better ways(like not iterating throught the whole list of modis each time we want a single month object (use a dictionary)) but the gist is the same.
I have looking into this issue for a while, but have yet to find a suitable answer (most involve switching to setChoiceValues() rather than addressing the "Cannot convert Array to Choice[]" issue with setChoices([])).
While attempting to generate form sections and questions via Google Script, I ran into the issue of not getting my answer selections to go to specific pages based on the user's answer. This appears to be the difference between setChoiceValues() and setChoices([]), with the latter allowing for page navigation as best as I can tell.
However, when attempting to put my array of new choices into setChoices([]), I get the error message "Cannot convert Array to Choice[]". My code works fine otherwise, but I need to use setChoices([]) (it seems) in order to get the page navigation that I want.
How can I loop values into an array or other container and be able to make them appear as a Choices[] object? How can I make something like this work? It seems like it should be much easier than it is, but I cannot see the solution.
Below is a segment of my code that is causing the issue:
//Form - globally accessible
var f = FormApp.openById(f_id);
//Date Iterator
var curr_date = 0;
//Time Iterator
var curr_time = 0;
//Array of Times
var Tchoices = [];
//Setting Time choices per date
while(curr_date < dates.length)
{
Tchoices = [];
curr_time = 0;
//dates is an array of objects with both d's (single date) and t's
// (array of times for that date)
var d = dates[curr_date].d;
var end_break = f.addPageBreakItem().setTitle("Times for " + d);
var f_time = f.addMultipleChoiceItem().setTitle(d);
while(curr_time < dates[curr_date].t.length)
{
end_break = end_break.setGoToPage(FormApp.PageNavigationType.SUBMIT);
Tchoices.push(f_time.createChoice(dates[curr_date].t[curr_time], end_break).getValue());
curr_time++;
}
f_time.setChoices([Tchoices]);
}
There was some minor issues with the building of your MultipleChoise object:
//Form - globally accessible
var f = FormApp.openById('someID');
//Date Iterator
var curr_date = 0;
//Time Iterator
var curr_time = 0;
//Array of Times
var Tchoices = [];
//Setting Time choices per date
while(curr_date < dates.length)
{
Tchoices = [];
curr_time = 0;
//dates is an array of objects with both d's (single date) and t's
// (array of times for that date)
var d = dates[curr_date].d;
var end_break = f.addPageBreakItem().setTitle("Times for " + d);
var f_time = f.addMultipleChoiceItem();
f.addMultipleChoiceItem().setTitle(d);
while(curr_time < dates[curr_date].t.length) //verify this while not sure what you have inside your dates array
{
end_break = end_break.setGoToPage(FormApp.PageNavigationType.SUBMIT);
Tchoices.push(f_time.createChoice(dates[curr_date].t[curr_time])); //You cannot add a pagebreak inside the elements of a choiseItem array
curr_time++;
}
Logger.log(Tchoices);
f_time.setChoices(Tchoices);
}
Check the values for dates[curr_date].t.length inside the Loop I'm not sure how you constructed the array.
You cannot add a pagebreak inside the elements of a choiseItem array
I have a very simple JS Arrays question, my simple canvas game has been behaving differently when I replaced one block of code with another. Could you look them over and see why they are functionally different from one another, and maybe provide a suggestion? I may need these arrays to have 20+ items so I'm looking for a more condensed style.
There's this one, which is short enough for me to work with, but doesn't run well:
var srd=new Array(1,1,1);
var sw=new Array(0,0,0);
var sang=new Array(0,0,0);
var sHealth=new Array(20,20,20);
And then there's the original one, which is longer but works fine:
var srd = new Array();
srd[1] = 1;
srd[2] = 1;
srd[3] = 1;
var sw = new Array();
sw[1] =0;
sw[2] =0;
sw[3] =0;
var sang = new Array();
sang[1] = 0;
sang[2] = 0;
sang[3] = 0;
var sHealth = new Array();
sHealth[1] = 20;
sHealth[2] = 20;
sHealth[3] = 20;
Arrays are zero-indexed in JavaScript. The first element is 0, not 1:
var srd = new Array();
srd[0] = 1;
srd[1] = 1;
srd[2] = 1;
Also, you may want to use the more common array constructor:
var srd = [1, 1, 1];
I have a feeling that you may be assuming that the first element is 1 instead of 0, which is why the first version doesn't work while the second one does.
You should do this....in Arrays values are stored as such that first one is at 0 and so on.
so 1st value will be accessed as this...
var x = abc[0]; //first value of array abc being assigned to x.
Do this (you see i actually read your question and this is what you like)
var srd=['',1,1,1];
var sw=['',0,0,0];
var sang=['',0,0,0];
var sHealth=['',20,20,20];
you can declare an array(object) in javascript like this
var x = []; -------------Literal - its a shortcut provided by JS to quickly declare something as an Array.
var x = new Array; --Array constructor
Things to look up regarding
literal
object literal
proto
word new
function object
function property prototype
You can also do these:
var x=1,y=2,
z=3,
f;
var b = something || {}; \\become a copy of object called something if it's not there then become an empty object.
It looks like one starts the arrays at index 0 and the other one starts at index 1
It depends on your implementation, but it's likely because of arrays being 0-indexed. In your first block of code, each number is offset by one index spot from the second block. The first one is equivalent to:
var srd = new Array();
srd[0] = 1;
srd[1] = 1;
srd[2] = 1;
in the way you wrote it for the second block.
What's the most efficient way to declare and populate a multidimensional array in JavaScript?
I'm currently doing this:
ff = Array();
for (i = 0; i < 30; i++) {
ff[i] = Array();
ff[i][i] = 1.0;
}
ff[1][2] = 0.041666667;
ff[1][3] = 0.000694444;
ff[2][3] = 0.016666667;
ff[1][4] = 0.000011574;
ff[2][4] = 0.000277778;
ff[3][4] = 0.016666667;
ff[1][5] = 0.000011574;
ff[2][5] = 0.000035315;
ff[3][5] = 0.00211888;
ff[4][5] = 0.1271328;
ff[1][6] = 0.000000025;
ff[2][6] = 0.000000589;
ff[3][6] = 0.000035315;
ff[4][6] = 0.00211888;
ff[5][6] = 0.016666667;
up to ff[n][n] where n can be up to 30, which leads to hundreds of lines of declaring array values (does this matter, even when minified?). I only need to populate the "top" half of the array since ff[n][n] = 1 and ff[i][j] = 1/(ff[j][i]) so after the declaration I loop over the whole array and invert the "top" half to populate the "bottom" half.
From looking at your numbers, it looks like you're trying to convert between various time units.
I wonder if a better fit wouldn't be an object.
var seconds = {
day: 86400,
hour: 3600,
minute: 60,
second: 1
};
var conversions = {};
['day','minute','hour','second'].forEach(function(fromUnit){
var subConversions = {};
var fromValue = seconds[fromUnit];
['day','minute','hour','second'].forEach(function(toUnit){
subConversions[toUnit] = fromValue / seconds[toUnit];
});
conversions[fromUnit] = subConversions;
});
function convert(value, from, to){
return value * conversions[from][to];
}
This will give you.
convert(1, 'day','hour') === 24
convert(1, 'day','second') === 86400
convert(3, 'hour','second') === 10800
Even if things are more complicated than simple time conversion, this approach is probably going to lead to much more understandable code. Once you start giving the elements of a multi-dimensional array special meanings, things can get pretty ugly.
I would do something like the following: And then I would put the script in a separate file which can be cached.
ff=[];
ff[0]=[0.041666667,000694444,016666667,000277778,016666667];
ff[1]=[0.041666667,000694444,016666667,000277778,016666667];
ff[2]=[0.041666667,000694444,016666667,000277778,016666667];
ff[3]=[0.041666667,000694444,016666667,000277778,016666667];
ff[4]=[0.041666667,000694444,016666667,000277778,016666667];
ff[5]=[0.041666667,000694444,016666667,000277778,016666667];
var klas4 = [];
klas4[2] = [];
klas4[2]["hour"] = 1;
klas4[2]["teacher"] = "JAG";
klas4[2]["group"] = "V4A";
klas4[2]["subject"] = "IN";
klas4[2]["classroom"] = "B111";
klas4[0] = [];
klas4[0]["hour"] = 6;
klas4[0]["teacher"] = "JAG";
klas4[0]["group"] = "V4B";
klas4[0]["subject"] = "IN";
klas4[0]["classroom"] = "B111";
klas4[1] = [];
klas4[1]["hour"] = 4;
klas4[1]["teacher"] = "NAG";
klas4[1]["group"] = "V4A";
klas4[1]["subject"] = "NA";
klas4[1]["classroom"] = "B309";
This multidimensional array needs to be sorted by hour, ascending. The problem is, I don't know how to sort an multidimensional array. The first dimension (0, 1 and 2), needs to be changed, according to the hour, but all other details from dimension 2 (teacher, group etc.) also need to change from index, because otherwise the data is mixed.
You don't know how many indexes there are. In this example, the correct sequence should be: klas4[2][...], klas4[1][...], klas[0][...]
In PHP there's a certain function multisort, but I couldn't find this in jQuery or JavaScript.
klas4.sort( function(a,b){ return a.hour - b.hour } );
should do it.
It helps to think of klas4 not as a multi-array but as 1 array of objects.
Then you sort the objects in that array with a sort function.
The sort function takes 2 objects and you must return which one comes first.
You should read on sort() for Array, google that.
Also, as others have commented; the entries for klas4 are really objects, you should use
klas4[2] = {};
or even better
klas4[2] = { hour:1 , teacher:"JAG" , group:"V4A" , subject: "IN" };
Finally, I assume you are a native Dutch or German speaker, as I am. I would strongly suggest to name all your variables in English, class4, not klas4. It is the right, professional thing to do.