I have a spreadsheet where a lot of cells are multiplied with a CONSTANT value and added and the result (SOLL) differs from the expected (IST) value and the only way I was able to find, was to make 10 iterations modifying each time the CONSTANT value till the SOLL and IST are pretty equal.
My method looks too stupid and I am just asking a beautiful and intelligent way to solve it...
thanks
function costante()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); //spreadsheet "options"
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]); //sheet nr.1
var sheet = SpreadsheetApp.getActiveSheet();
for(var i=0; i<10; i++){
var dataRange = sheet.getRange("o5:o5"); //marge ist
var mist = dataRange.getValues();
var dataRange = sheet.getRange("o4:o4"); //marge soll
var msoll = dataRange.getValues();
var dataRange = sheet.getRange("n1:n1"); //costante
var costante = dataRange.getValues();
var minus = 1;
if(mist - msoll < 0) { minus = -1};
costante = mist / msoll * minus * costante;
sheet.getRange("n1:n1").setValues([[costante]]);}
}
Maybe what you want, assuming your "lot of cells" are in A1:A10 and the IST value is in E1 is:
=E1/sum(A1:A10)
but please note the tag wiki.
thanks, I was first surprised by the simple method and I checked it:
10 values and their addition gives for instance = 10 (sum(a1:a10))
the IST value that I would like to have is 500 (E1)
E1/sum(A1:A10) = 500/10 = 50 = C (COSTANTE)
E1 = Sum(A1:A10) x C
if I multiply each A(y) value with 50, I have 500 and the proposed formula would perfectly work
BUT I forgot to mention that the values of A(y) are formulas that include already my COSTANTE it means that in reality each A(y) value is a formula that contains C
E1 = Sum( A(y) x C ) x C
a) for that reason the solution proposed does not give the needed value, and I was obliged to repeat the calculation ca.10 times
b) I also added a delay of 1 second because I was not sure if the spreadsheet is able to calculate so fast (please tell me if it is necessary)
c) and I said that if the result is +/- 2 from expected value, to stop to calculate
It works but is still not beautiful...
function costante()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); //spreadsheet "options"
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]); //sheet nr.1
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("o5:o5"); //marge ist
var mist = dataRange.getValues();
for(var i=0; i<20; i++)
{
var dataRange = sheet.getRange("o4:o4"); //marge soll
var msoll = dataRange.getValues();
var dataRange = sheet.getRange("n1:n1"); //costante
var costante = dataRange.getValues();
var diff = msoll - mist;
if(diff < -2) { costante = costante * 1.005;}
else if (diff > 2) { costante = costante * 0.995;}
else {return;}
sheet.getRange("n1:n1").setValues([[costante]]);
Utilities.sleep(1000); //wait 1.5sec
}
}
Related
So I have a sheet with about 800 rows. What I need to do is copy and paste each one 120 times. Instead of doing this manually I am hoping there is an automated way to do this in one shot. I have searched for a few things but everything I found had to do with copying the rows conditionally.
I don't need conditions. I just need all, each one of the 800 rows to be duplicated 120 times.
Any help or ideas is greatly appreciated.
Cheers
Modified #SpiderPig code to clone in a interleaved fashion
function duplicateRows() {
var sheet = SpreadsheetApp.getActiveSheet()
var numRows = sheet.getLastRow()
var numColumns = sheet.getLastColumn()
var numberOfClones = 120
for(var i = 0; i < numRows; i++) {
range = sheet.getRange((i*numberOfClones)+ 1, 1, 1, numColumns);
sheet.insertRows((i*numberOfClones)+ 2, numberOfClones-1)
range.copyTo(sheet.getRange((i*numberOfClones)+ 2 , 1, numberOfClones-1, numColumns));
}
}
Also instead of using a loop with range.copyTo(destination) to paste 120 times, you can expand the destination range to 120 rows. It will automatically paste the same value over the entire range.
So instead of this
for(var i = 1; i <= 120; i++) {
range.copyTo(sheet.getRange(numRows * i + 1, 1, numRows, numColumns));
}
you can do this once
range.copyTo(sheet.getRange(numRows * i + 1, 1, 120*numRows, numColumns));
Here is a script that will copy all the rows in the current sheet 120 times.
function duplicateRows() {
var sheet = SpreadsheetApp.getActiveSheet(),
numRows = sheet.getLastRow(),
numColumns = sheet.getLastColumn(),
range = sheet.getRange(1, 1, numRows, numColumns);
for(var i = 1; i <= 120; i++) {
range.copyTo(sheet.getRange(numRows * i + 1, 1, numRows, numColumns));
}
}
So I have this function here that runs through T2:T:
=IF($D$29<$N2,"", AVERAGE(INDIRECT("P"&IF($N2<11, 2,$N2-5)&":P"&$N2+5)))
Column P is a list of numbers starting at row 2. Column N is an index(goes up by 1 each row) which starts at row 2 and ends where P ends + 14, and D29 is just a number. In my current situation P ends at row 11 and N ends at row 25. And I'm trying to change it into an array formula so that when I add new rows it updates automatically. So after changing it I got this:
=ARRAYFORMULA(IF($D$29<$N2:N,"", AVERAGE(INDIRECT("P"&IF($N2:N<11, 2,$N2:N-5)&":P"&$N2:N+5))))
However, it is not functioning properly. It still occupies the same amount of rows, but each row is the same value. The value of the first row originally. How can I fix this problem? Thanks!
The problem here is that ARRAYFORMULA doesn't work with AVERAGE.
But you could always use javascript.
Open up the script editor and paste in this code.
function avg(nums, d) {
var r = [],
i, j, start, end, avg, count;
for(i = 0; i < nums.length; i++) {
if(d <= i) r.push([""]);
else {
if(i < 10) start = 0;
else start = i - 5;
end = i + 4;
avg = 0, count = 0;
for(j = start; j <= end; j++) {
if(nums[j]) {
avg += nums[j][0];
count++;
}
}
r.push([avg / count]);
}
}
return r;
}
Save it, go back to your spreadsheet and put this formula in any cell =avg(P2:P11, D29)
I'm pushing the boundaries of experience here and cant see what I am doing wrong.
I'm pulling a bunch of data from a DB in rails, converting it to JSON and trying to plot it in d3.
The data is a simple JSON of {date => number} and the data is fine.
I'm doing something wrong with d3 in the loop at the bottom of the code but cant see what.
The axes plot fine but I can't get the line to draw.
Here is my code:
var data = <%= #signups.to_json.html_safe %>;
var date, signups
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%Y").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(date)
.y(signups)
.interpolate("linear");
var svg = d3.select(".container").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Find range of data for domain
var min_date = Infinity, max_date = -Infinity;
var min_signups = Infinity, max_signups = -Infinity;
var x;
$.each(data, function(key, value) {
temp = parseDate(key)
if( temp < min_date) min_date = temp;
if( temp > max_date) max_date = temp;
if( +value < min_signups) min_signups = +value;
if( +value > max_signups) max_signups = +value;
});
x.domain([min_date, max_date]);
y.domain([0, max_signups]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
svg.append("path")
$.each(data, function(key, value) {
date = parseDate(key);
signups = value;
d3.select("path")
.append("svg")
.attr("d", d3.svg.line()
.x(date)
.y(signups)
.interpolate("linear"));
});
Any help would be greatly appreciated
The D3 way would be to pass all your data to a suitable line generator. This is fairly simple in your case, you just need to convert the object that contains all the data to an array that D3 can work with using d3.entries().
var line = d3.svg.line()
.x(function(d) { return x(parseDate(d.key)); })
.y(function(d) { return y(d.value); });
svg.selectAll("path").data([d3.entries(data)])
.enter().append("path").attr("d", line);
As you have only a single line, you could also use .datum() to bind the data, but using .data() leaves you the option of passing in data for more lines later.
Complete jsfiddle here. When modifying this, make sure that you create the line before adding the axes, otherwise D3's data matching won't work with the default matching and you won't get any lines. To fix this, you could supply a matching function, but to start with it's much easier to keep to this order.
Can anyone simplify and rearrange my script such that it works faster without stucking . This script was made to extract spreadsheet data from 4 spreadsheets and deleting blank rows based on a column criteria, This script is working well but taking long time and suddenly/often breaks process saying that spreadsheet page needs to refresh thus stopping the entire process. which should follow with rerunning the script. - Thanks in advance.
my script is as follows :
function myFunction() {
// spreadsheets key to extract data.
//Bhaskar 0AjkkHlm3kCphdFh3M2dtRDdoZHhWZlg5UzFjSWZFcVE
//RAmohan 0AjkkHlm3kCphdGFlNTVhSDc5VXVTeS0xc2ZISDRGZlE
//Krishnareddy 0AjkkHlm3kCphdEhDWEllalpoM3VmNE5weUNLZkd4TVE
//Suni 0AjkkHlm3kCphdFUxTXJlN3lGYkRMY2NXUUkzSTVfbEE
var copieddata = SpreadsheetApp.openById('0AjkkHlm3kCphdFh3M2dtRDdoZHhWZlg5UzFjSWZFcVE').
getSheetByName('List').getDataRange().getValues();
//getSheetByName('List').getRange('I6:AT500').getValues();
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
SpreadsheetApp.setActiveSheet(s1);
//getRange(StartingROWS(1,2,3,4,...),StartingCOLUMNS(A,B,C,D..),
s1.getRange(1,1,copieddata.length,copieddata[0].length).setValues(copieddata);
//var col1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumColumns();
//var row1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumRows();
SpreadsheetApp.flush(); //force the data to be written
// here ends sheet 1 -------
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var numRows = sheet.getLastRow();
var datasheet = sheet.getDataRange();
var data = datasheet.getValues();
//Browser.msgBox(" data lenght -" + data.length + " rage is " + datasheet);
for (var i = data.length; i > 0; --i){
var ii=i-1;
var row = data[ii];
var name = row[6];
var len = name.length;
//Browser.msgBox("row number" + i + " ->" + row[10] + "<- its length =" + len);
if(name.length!=3){
//Browser.msgBox("delete ." + i);
sheet.deleteRow(i);
}
SpreadsheetApp.flush(); //force the data to be written
}
SpreadsheetApp.flush(); //force the data to be written
// ------------------
var lrange = SpreadsheetApp.getActiveSheet().getLastRow();
//Browser.msgBox("l range - " + lrange);
var copieddata = SpreadsheetApp.openById('0AjkkHlm3kCphdGFlNTVhSDc5VXVTeS0xc2ZISDRGZlE').
getSheetByName('List').getDataRange().getValues();
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
SpreadsheetApp.setActiveSheet(s1);
s1.getRange((lrange+1),1,copieddata.length,copieddata[0].length).setValues(copieddata);
//var col1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumColumns();
//var row1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumRows();
SpreadsheetApp.flush(); //force the data to be written
// here ends sheet 2 -------
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var numRows = sheet.getLastRow();
var datasheet = sheet.getDataRange();
var data = datasheet.getValues();
//Browser.msgBox(" data lenght -" + data.length + " rage is " + datasheet);
for (var i = data.length; i > 0; --i){
var ii=i-1;
var row = data[ii];
var name = row[6];
var len = name.length;
//Browser.msgBox("row number" + i + " ->" + row[10] + "<- its length =" + len);
if(name.length!=3){
//Browser.msgBox("delete ." + i);
sheet.deleteRow(i);
}
SpreadsheetApp.flush(); //force the data to be written
}
// ------------------
var lrange = SpreadsheetApp.getActiveSheet().getLastRow();
//Browser.msgBox("l range - " + lrange);
var copieddata = SpreadsheetApp.openById('0AjkkHlm3kCphdEhDWEllalpoM3VmNE5weUNLZkd4TVE').
getSheetByName('List').getDataRange().getValues();
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
SpreadsheetApp.setActiveSheet(s1);
s1.getRange((lrange+1),1,copieddata.length,copieddata[0].length).setValues(copieddata);
//var col1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumColumns();
//var row1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumRows();
SpreadsheetApp.flush(); //force the data to be written
// here ends sheet 3 -------
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var numRows = sheet.getLastRow();
var datasheet = sheet.getDataRange();
var data = datasheet.getValues();
//Browser.msgBox(" data lenght -" + data.length + " rage is " + datasheet);
for (var i = data.length; i > 0; --i){
var ii=i-1;
var row = data[ii];
var name = row[6];
var len = name.length;
//Browser.msgBox("row number" + i + " ->" + row[10] + "<- its length =" + len);
if(name.length!=3){
//Browser.msgBox("delete ." + i);
sheet.deleteRow(i);
}
SpreadsheetApp.flush(); //force the data to be written
}
// ------------------
var lrange = SpreadsheetApp.getActiveSheet().getLastRow();
//Browser.msgBox("l range - " + lrange);
var copieddata = SpreadsheetApp.openById('0AjkkHlm3kCphdFUxTXJlN3lGYkRMY2NXUUkzSTVfbEE').
getSheetByName('List').getDataRange().getValues();
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
SpreadsheetApp.setActiveSheet(s1);
s1.getRange((lrange+1),1,copieddata.length,copieddata[0].length).setValues(copieddata);
//var col1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumColumns();
//var row1count = SpreadsheetApp.getActiveSheet().getRange(1,1,copieddata.length,copieddata[0].length).getNumRows();
SpreadsheetApp.flush(); //force the data to be written
// here ends sheet 4 -------
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var numRows = sheet.getLastRow();
var datasheet = sheet.getDataRange();
var data = datasheet.getValues();
//Browser.msgBox(" data lenght -" + data.length + " rage is " + datasheet);
for (var i = data.length; i > 0; --i){
var ii=i-1;
var row = data[ii];
var name = row[6];
var len = name.length;
//Browser.msgBox("row number" + i + " ->" + row[10] + "<- its length =" + len);
if(name.length!=3){
//Browser.msgBox("delete ." + i);
sheet.deleteRow(i);
}
SpreadsheetApp.flush(); //force the data to be written
}
}
spreadsheet link is as follows : Clik here to enter into my spreadsheet
here's my attempt:
function myFunction2() {
var source = ['0AjkkHlm3kCphdFh3M2dtRDdoZHhWZlg5UzFjSWZFcVE',
'0AjkkHlm3kCphdGFlNTVhSDc5VXVTeS0xc2ZISDRGZlE',
'0AjkkHlm3kCphdEhDWEllalpoM3VmNE5weUNLZkd4TVE',
'0AjkkHlm3kCphdFUxTXJlN3lGYkRMY2NXUUkzSTVfbEE'];
var copied = [];
for (var i = 0; i < source.length; i++) {
copied = copied.concat(SpreadsheetApp.openById(source[i]).getSheetByName('List').getDataRange().getValues());
}
for (var j = 0; j < copied.length; j++) {
if (copied[j][6].length != 3) {
copied.splice(j, 1);
j--;
}
}
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
sheet.clearContents();
sheet.getRange(1, 1, copied.length, copied[0].length).setValues(copied);
}
In this I create one big javascript array from the four spreadsheets, remove elements ("rows") from that array (rather than deleting rows in the spreadsheet itself which I presume is the reason why it's slow), clear the destination sheet, and set the values of the modified array in one go.
HTH
Adam
I hope that someone can shed a light on the (to me) unexpected behavioral difference between the two (result wise) equal queries.
A small program can be worth a thousand words, so here goes :
static void Main(string[] args)
{
var l1 = new List<int> { 1, 2, 3 };
var l2 = new List<int> { 2, 3, 4 };
var q1 = // or var q1 = l1.Join(l2, i => i, j => j, (i, j) => i);
from i in l1
join j in l2
on i equals j
select i;
var q2 = //or var q2 = l1.SelectMany(i => l2.Where(j => i == j));
from i in l1
from j in l2
where i == j
select i;
var a1 = q1.ToList(); // 2 and 3, as expected
var a2 = q2.ToList(); // 2 and 3, as expected
l2.Remove(2);
var b1 = q1.ToList(); // only 3, as expected
var b2 = q2.ToList(); // only 3, as expected
// now here goes, lets replace l2 alltogether.
// Afterwards, I expected the same result as q1 delivered...
l2 = new List<int> { 2, 3, 4 };
var c1 = q1.ToList(); // only 3 ? Still using the previous reference to l2 ?
var c2 = q2.ToList(); // 2 and 3, as expected
}
Now I know that Join internally uses a lookup class to optimize performance, and without too much knowledge, my guess is that the combination of that with captured variables might cause this behavior, but to say I really understand it, no :-)
Is this an example of what Joel calls "a leaky abstraction" ?
Cheers,
Bart
You're actually nearly there, given your query expansions in the comments:
var q1 = l1.Join(l2, i => i, j => j, (i, j) => i);
var q2 = l1.SelectMany(i => l2.Where(j => i == j));
Look at where l2 is used in each case. In the Join case, the value of l2 is passed into the method immediately. (Remember that the value is a reference to the list though... changing the contents of the list isn't the same as changing the value of l2.) Changing the value of l2 later doesn't affect what the query returned by the Join method remembers.
Now look at SelectManay: l2 is only used in the lambda expression... so it's a captured variable. That means that whenever the lambda expression is evaluated, the value of l2 at that moment in time is used... so it will reflect any changes to the value.