Have anyone had performance issue when creating a select all / deselect all on the toolbar and the update is very slow. It took around 10 seconds to iterate through 300 records in the grid using the datasource set/get methods.
The code I used is as follows:
var data = dataSource.view();
for (var idx = 0, length = data.length; idx < length; idx++) {
if (!data[idx].IsActive) data[idx].set("IsActive", true);
}
Anyone encountered this issue? Is there a way to improve the performance?
Thanks.
Three questions:
if you are going to set IsActive to true, don't spend time checking if it is already true;
Instead of setting it assign the value directly, set is a pretty expensive operation and then do a refresh to update the UI.
Your computer is much faster than mine, in my case 300 values took much longer ;-)
Try doing:
var data = dataSource.view();
for (var idx = 0, length = data.length; idx < length; idx++) {
data[idx].Active = true;
}
grid.refresh();
Instead of calculating length of data everytime ,store length in local variable
like this
var data = dataSource.view();
var dataLength=data.length;
for (var idx = 0, length = dataLength; idx < length; idx++) {
data[idx].Active = true;
}
grid.refresh();
Related
=>I don't speak English
=>Using google translate
I have an app Script that uses a for loop to write a value to a cell but too many rows(30000). Recording takes a lot of time. So is there any solution to shorten the time?
var dataValues = dataRange.getValues();
for(var i = 6; i < 30000; i++)
{
if(dataValues[i][0]!== '')
{
var tudongxonghang = i+1;
dataSheet.getRange('B' + tudongxonghang).setValue("hello");
1. Code description: I wrote this app script that for each row, colors the cell in column A the same color as the last cell of that row with text in it. Additionally, I use an onEdit trigger, so whenever I edit a row, the script runs. This worked alright when I had about 20 rows and 20 columns (2-3 seconds).
2. Problem: I now have a sheet with about 200 rows and 20 columns and the code is extremely slow (3-4 minutes or more).
3. QUESTION: How to make it run faster, or, given what I need, should I write this task in another way?
4. Solutions I thought about but don't like:
split my sheet into several sheets (not as helpful for my use case)
add a button to run the app only when I make an edit (not as nice as an onEdit)
5. Code:
function colorFirstCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('courseX');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var columnFirstCells = 1; // column of cell to be colored
var dataRange = sheet.getRange(1,1, lastRow, lastColumn + 1).getValues();
for(var i = 0; i < lastRow; i++)
{
for(var j = 0; j < lastColumn; j++) {
if(dataRange[i][j] != '' && dataRange[i][j+1] == '') { // cell not empty and cell to the right is empty
var backgroundColor = sheet.getRange(i + 1, j + 1).getBackground(); // get color
sheet.getRange(i + 1, columnFirstCells).setBackground(backgroundColor); // set color
of first col cell
}
}
}
}
I believe your goal is as follows.
You want to reduce the process cost of your script.
In this case, how about the following modification?
Modified script:
function colorFirstCell2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('courseX');
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
var backgrounds = range.getBackgrounds();
var colors = range.getDisplayValues().map((r, i) => {
for (var j = r.length - 1; j >= 0; j--) {
if (r[j] != "") {
return [backgrounds[i][j]];
}
}
return [null];
});
sheet.getRange(1, 1, colors.length).setBackgrounds(colors);
}
In this case, first, the values and background colors are retrieved from the data range. And then, an array including the background colors is created. And, the created array is put to the column "A".
References:
map()
setBackgrounds(color)
Which of the following queries are considered heavier performance wise:
//*/*/*/*/*
or
//ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*
or
/descendant-or-self::*/*/*/*
To my understanding the second would be more complex to compute?
Thanks.
About time of execution: it does not have a noticeable difference due to the fact that exist a lot of affecting factors, but anyway with almost identical tiny execution time of each requests.
On the current page each of requests performed on average in 0.07–0.09µs; 1µs = 1second * 10^-6.
let arrExecutionTime = [];
function getAverageExecutionTime(locator) {
let maxIteration = 1000;
let timeTotal = 0;
for (let i = 0; i < maxIteration; i++) {
let executionTimeStart = performance.now();
let arrNode = document.evaluate(locator, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
arrExecutionTime.push(performance.now() - executionTimeStart);
}
for (let k = 0; k < arrExecutionTime.length; k++) {
timeTotal += arrExecutionTime[k];
}
let avgExecutionTime = timeTotal / arrExecutionTime.length;
console.log(`avgExecutionTime: ${avgExecutionTime}µs \nafter ${maxIteration} iterations \nfor locator:\"${locator}\"`);
}
getAverageExecutionTime("//*/*/*/*/*");
getAverageExecutionTime("//ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*");
getAverageExecutionTime("/descendant-or-self::*/*/*/*");
I have CouchDB view that gives me a correct value in natural order and a null when sorted descending, here are the Futon screenshots:
Natural order
Descending order
Here is the view code:
"informe_precios": {
"map": "function(doc){if(doc.doc_type=='precio'){emit([doc.comprador,doc.fecha.substr(0,4),doc.fecha.substr(5,2)],{precio:doc.precio,litros:doc.litros});}}",
"reduce": "function(keys, values, rereduce){var importe= 0; var totallitros = 0;for(var i = 0; i < values.length; i++) {importe += values[i].precio*values[i].litros;totallitros += values[i].litros;}return importe/totallitros;}"
}
I need it descending because I want to get 12 last values.
TIA
Diego
You're always assuming that your reduce function is called with the output of your map function, ie. you're not handling the rereduce situation.
In the rereduce your values will be the importe/totallitros values from previous reduce calls.
Your reduce function is getting a "price per liter" average for each month, so because it's an average there's no way for your rereduce function to actually handle that data because for the multiple values coming in there's no way to know their weight in the average.
So, you'll need to change your function to return the count so that you can use that to weight the average in the rereduce function (we're also using the inbuilt sum function to make things simpler):
function(keys, values, rereduce) {
if (rereduce) {
var length = sum(values.map(function(v){return v[1]}));
var avg = sum(values.map(function(v){
return v[0] * (v[1] / length)
}));
return [avg, length];
}
else {
var importe= 0;
var totallitros = 0;
for( var i = 0; i < values.length; i++) {
importe += values[i].precio * values[i].litros;
totallitros += values[i].litros;
}
return [ importe/totallitros, values.length ];
}
}
The final result you'll see in your view here will be an array, so you'll always need to pick out the first element of that in your client code.
I really wish Processing had push and pop methods for working with Arrays, but since it does not I'm left trying to figure out the best way to remove an object at a specific position in an array. I'm sure this is as basic as it gets for many people, but I could use some help with it, and I haven't been able to figure much out by browsing the Processing reference.
I don't think it matters, but for your reference here is the code I used to add the objects initially:
Flower[] flowers = new Flower[0];
for (int i=0; i < 20; i++)
{
Flower fl = new Flower();
flowers = (Flower[]) expand(flowers, flowers.length + 1);
flowers[flowers.length - 1] = fl;
}
For the sake of this question, let's assume I want to remove an object from position 15. Thanks, guys.
You may also want to consider using ArrayList which has more methods available than a plain array.
You can remove the fifteenth element by using myArrayList.remove(14)
I made a funtion which basically switches the index to be removed to the last and then shortens it.
int[] removeByIndex(int[] array, int index) {
int index2 = array.length-1;
int old = array[index];
array[index] = array[index2];
array[index2] = old;
array = shorten(array);
return array;
}
yourarray = removeByIndex(yourarray , arrayindex);
hope this helps!
I think that your best bet is to use arraycopy. You can use the same array for src and dest. Something like the following (untested):
// move the end elements down 1
arraycopy(flowers, 16, flowers, 15, flowers.length-16);
// remove the extra copy of the last element
flowers = shorten(flowers);
String[] myArray = { "0", "1", "2", "3", "4", "5", "6"};
String[] RemoveItem(String[] arr, int n) {
if (n < arr.length-1) {
arrayCopy(subset(arr, n+1), 0, arr, n, arr.length-1-n);
}
arr = shorten(arr);
return arr;
}
I know this question was asked a long time ago however it seems a lot of people are still looking for the answer. I just wrote this. I tested it a few ways and it seems to run the way I wanted it to.
var yourArr = [1, 2, 3, 4]; // use your array here
var removeIndex = 1; // item to get rid of
var explode = function(array, index) { // create the function
var frontSet = subset(array, 0, index - 1); // get the front
var endSet = subset(array, index , array.length - 1); // get the end
yourArr = concat(frontSet, endSet); // join them
};
explode(yourArr, removeIndex); // call it on your array
That is one way. I guess you could loop through the array as well. Something like ...
var yourArr = [1, 2, 3, 4];
var removeIndex = 2;
var newArr = [];
for(var i = 0; i < yourArr.length; i++) {
if(i < removeIndex) {
append(newArr, yourArr[i]);
} else if(i > removeIndex) {
append(newArr, yourArr[i]);
}
}
yourArr = newArr;
... think that should work too. Hope this helps anybody who needs it.