I have a column which contains a string like
1.000*2.000*5.000
Are there any way to get it evaluated and return the result in a new column?
One way you can do this is with a Javascript function:
create or replace function multiply(s string)
returns float
language javascript
as
'
var numbers = S.split("*");
var total = 1;
for (var i = 0; i < numbers.length; i++) {
total *= parseFloat(numbers[i]);
}
return total;
';
Then:
select multiply('1.000*2.000*5.000');
Gives me:
10
Of course, using floats that in a form of 1.001 shows a float result:
select multiply('1.001*2.000*5.000');
gives me:
10.01
Related
I am having a issue getting my code to return the correct value.
I am building spreadsheet to help me with cooking for a video game I play. I am trying to track the amount of all the ingredients I have for cooking. I want to be able to update the amount I have from a dashboard rather than go scroll through the list to find each ingredient individually.
Here is what I have setup so far.
I have a page called Updater where I am selecting from a drop down a certain ingredient(cell A2). Next to that drop down is cell for me to enter a new amount of that ingredient that I have(cell B2).
The second page is called Ingredients. This has a 2 columns. Column 1 is a list of the ingredients and in column 2 is the number I currently have on hand.
The script I have written so far can find me the row number, but when I try to get the current amount I have for the ingredient to make sure the code is working, it doesnt return anything in the log.
There is my code
function finalTest(){
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var fs = spreadsheet.getSheetByName("Ingredients");
var ts = spreadsheet.getSheetByName("Updater");
var data = fs.getDataRange().getValues();
var luItem = ts.getRange("A2").getValue();
var newAmt = ts.getRange("B2").getValue();
var rn = 0;
Logger.log(rn);
Logger.log(newAmt);
Logger.log(data);
Logger.log(luItem);
for(var i = 0; i<data.length;i++){
if(data[i][0] == luItem){ //[1] because column B
Logger.log((i+1))
return i+1;
}
}
rn = i;
Logger.log(rn);
var fsr = fs.getRange(rn,2).getValue();
Logger.log(fsr);
}
Right now the logger will return up to where it logs "i", but will not return the new rn or fsr values.
Any help would be greatly appreciated.
A function immediately returns on the return statement. So you can only return one value there - or an object with multiple values inside.
As it looks that you just want to log data out, you would have to do that inside the if, but before the return to reach:
for (var i = 0; i < data.length; i++) {
if (data[i][0] == luItem) {
// first do all the logging
Logger.log(i + 1);
rn = i;
Logger.log(rn);
var fsr = fs.getRange(rn,2).getValue();
Logger.log(fsr);
// and then return from the function
return i + 1;
}
// what should be returned here??
}
Please also note that you should return a value or handle it somehow else when the loop runs through and the condition is never met.
If the return value then is still i + 1, you could make the if-condition instead part of the stop condition of the loop:
var i = 0;
for (; (i < data.length) && (data[i][0] == luItem); i++);
// no loop body needed here!
// do the logging outside the loop
Logger.log(i + 1);
rn = i;
Logger.log(rn);
var fsr = fs.getRange(rn,2).getValue();
Logger.log(fsr);
// and then return from the function
return i + 1;
The goal of the loop is to fill each cell over 797 rows across 5 columns A, B, C, D and E with a formula whose cell reference increments by 1.
E.g. Column A rows 6 onwards will have formula "=indirect("'Data Repository'!A3++")"
Column B rows 6 onwards will have formula "=indirect("'Data Repository'!B3++")"
What happens when I run the function however is it only fills in column A. I've checked the execution transcript and execution succeeded is logged after the first column has been filled up. I've tried various variations to no avail.
Below is the last variation I've tested:
function indirect(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Fleet - Weekly V3");
var formulaArray = [];
var columns = ["A","B","C","D","E"];
var row = 2;
var text = '=indirect(\"\'Data Repository\'!';
var headerRow = 6;
var column;
for(i = 0; i < 5; i++) {
column = parseInt(i) + 1;
formula = text + columns[i];
for(i = 0; i < 797; i++) {
row += 1;
if (formulaArray.length == 797) {
sheet.getRange(headerRow, column).offset(0, 0, formulaArray.length).setValues(formulaArray);
} else {
formulaArray.push([formula + row + '")']);
}
Logger.log(formulaArray.length);
}
Logger.log(i)
formulaArray = [];
}
}
Here is where you might be making an error - you need to create the variable i (var i = 0 instead of just i = 0) and if you're nesting loops, you need to have different variables increasing (first loop use i, then nest with j, then nest in that with k etc as needed)
for(var i = 0; i < 5; i++) {
column = parseInt(i) + 1;
formula = text + columns[i];
for(var j = 0; j < 797; j++) {
Untested but I believe it should work if you just substitute that in.
Your problem is in your loops. You are using the 'i' variable twice. Change the for loop that you have nested to iterate over the variable 'j' or something other than 'i'.
I'm looking for the fastest way to pick a random object that has a certain condition (from an array).
In the example below I have a multidimensional array, 50 * 50 that contains objects. I want to pick a random object from that array but that object needs to have a size larger than 100.
while (object.size <= 100)
{
attempts++;
object = grid_array[Math.round(Math.random() * 49)][Math.round(Math.random() * 49)];
}
Currently I have tested this and in some instances it takes over 300+ attempts. Is there a more elegant way to do this?
Thanks,
What I would do is first filter the source array to extract only valid candidates, then return a random one (if there are any).
For example:
function getRandomObject(grid_array:Array, minSize:Number):Object {
var filtered:Array = [];
for(var i:int = 0; i < grid_array.length; i++){
var inner:Array = grid_array[i];
for(var ii:int = 0; ii < inner.length; ii++){
var object:Object = inner[ii];
if(object.size >= minSize){
filtered.push(object);
}
}
}
return filtered.length ? filtered[int(Math.random() * filtered.length)] : null;
}
// example:
var object:Object = getRandomObject(grid_array, 100);
if(object){
// do stuff with `object`
}
I asked if you need the indexes because you could do this with RegExps and the JSON Class (Flash Player 11). With this example I stored the indexes of the objects:
Create random multidimensional Array to test the function
//---I stored a variable size and the indexes inside the Object
//---Size variable will be numbers between 0 and 500
var array:Array = [];
var i;
var j;
var size:uint = 50;
var obj:Object;
for(i = 0; i < size; i++){
array[i] = [];
for(j = 0; j < size; j++){
obj = new Object();
obj.size = Math.floor(Math.random() * 500);
obj.files = i;
obj.columns = j;
array[i][j] = obj;
}
}
Method to get random Object with size property bigger than 100
//---I'll use to search the object a JSON string
var str:String = JSON.stringify(array);
//---Function to get the random Object
function getRandom():Object{
//---RegExp to search object with size between 100 and 500
var reg:RegExp = /\{[^\}]*"size":(?:10[1-9]|1[1-9]\d|[2-5]\d\d)[^\}]*\}/g;
//---Get all matches
var matches:Array = str.match(reg);
//---Return a random match converted to object
//---If no match founded the return will be null
return matches ? JSON.parse( matches[Math.floor(Math.random() * matches.length)] ) : null;
}
I have an array that randomly creates 10 dots. However there's a certain area where I do not want them to be created. How can I achieve this? My code gives me error 2025.
"The supplied DisplayObject must be a child of the caller."
It will occasionally output the totalDots as instructed, (trace""+totalDots), but 90% of the time it will give me the error.
public var numDots:Array = [];
public var totalDots:int = numDots.length;
public var box:Box = new Box();
public function addBox():void
{
box.x = stageWidth/2;
box.y = stageHeight/2;
addChild(box);
}
private function addDot():void
{
for(var i:int = 0; i < 10; i++)
{
var dot:Dot = new Dot();
dot.x = Math.floor(Math.random() * stageWidth);
dot.y = Math.floor(Math.random() * stageHeight);
this.addChild(dot);
totalDots++;
trace(""+totalDots);
for(var j:int = 0; j < totalDots; j++)
{
if(numDots[j].hitTestObject(box))
{
stage.removeChild(numDots[j]);
numDots.splice(j, 1);
totalDots--;
}
}
}
}
Your problem is your nested loop. With each iteration, you add one new dot, and then loop over all of the existing ones, and remove them if it collides with the box. I don't think that's what you intended to do.
It looks like you just want to make sure the dots are not added within a certain area. In that case, keep it simple with a do while loop:
for(var i:int = 0; i < 10; i++)
{
var dot:Dot = new Dot();
this.addChild(dot);
do {
dot.x = Math.floor(Math.random() * stageWidth);
dot.y = Math.floor(Math.random() * stageHeight);
} while(dot.hitTestObject(box))
totalDots++;
trace(""+totalDots);
}
You never add any dot to your array.
You add the dot to the display list like so:
this.addChild(dot);
and you try to remove it like so:
stage.removeChild(numDots[j]);
Despite the fact that the dot is never added to the array, this couldn't have worked even if it was. That's because this is not stage. They are two different things.
You should never use stage.addChild() (check the documentation for more info on that). Just call addChild() all the time which is equivalent to this.addChild(). This ensures that you always operate on one and the same DisplayObjectContainer
For what it's worth, you can avoid the trial loop altogether by calculating a random value with the proper interval (the difference between the include and exclude areas) and deriving x and y coordinates from that.
The following code (written in a language I do not know, apologies if the syntax is faulty) has two cases. The if case handles the situation where the dot will appear left or right of the exclusion box, and the range of x values is restricted to being left or right of that box. The else case is where the dot will appear above or below the box, and the x values are not restricted.
var interval:int = stageWidth * stageHeight - box.w * box.h;
var cut:int = interval - (stageWidth - box.w) * box.h;
for (var i:int = 0; i < 10; i++) {
var r:int = Math.floor(Math.random() * interval);
var x:int;
var y:int;
if (r >= cut) {
r -= cut;
y = r / (stageWidth - box.w);
x = r - y * (stageWidth - box.w);
y += box.y;
if (x >= box.x) x += box.w;
} else {
y = r / stageWidth;
x = r - y * stageWidth;
if (y >= box.y) y += box.h;
}
var dot:Dot = new Dot();
dot.x = x;
dot.y = y;
this.addChild(dot);
totalDots++;
trace(""+totalDots);
}
This assumes that box is entirely within stageWidth,stageHeight.
Also notable is that it allows the dots to overlap; same as the original code.
For more complex shapes you can set box to the largest rectangle fully enclosed by that shape so as to avoid many but not all retry cases. This can be helpful for large shapes and many dots. Or there are variations which might manage a perfect fit to another shape (eg., an ellipse).
I am using LibSVM to carry out some multi-class classifications. I trained the model using the MATLAB interface of LibSVM. I then saved this model in a format that would be recognized in C. I now want to classify using svm_predict in C. I am having trouble being able to reproduce the results that I saw in MATLAB. In fact I get the same class output irrespective of what test vector I feed in (even a vector of zeros) I think the issue is with the way I am loading the test vector x into the svm_node structure. Below is the code snippet. Do let me know if this is correct way or if I am missing something.
struct svm_model *libsvm_model = svm_load_model('mymodel.svm');
struct svm_node x[2001]; // this is for one feature vector of size 2000x1
int index = 1;
int i = 0;
for (i = 0; i < features.size(); i++) {
x[i].index = index;
x[i].value = features.at(i);
index = index + 1;
}
x[i+1].index = -1;
x[i+1].value = '?';
double result = svm_predict(libsvm_model, x);
This seems to be a problem:
x[i+1].index = -1;
x[i+1].value = '?';
libsvm requires svm_node to be an input vector, which should have positive indexes, and double values. You should not "leave" some weird empty dimension.
And by the way, you don't need index variable
for (i = 0; i < features.size(); i++) {
x[i].index = index;
x[i].value = features.at(i);
index = index + 1;
}
is equivalent to
for (i = 0; i < features.size(); i++) {
x[i].index = i + 1;
x[i].value = features.at(i);
}