Changing positive numbers to negative numbers with custom number formats - and creating a script to execute this function - formatting

Looking for a means to change the positive numbers to negative with a script.
My reports have cells which will reflect the "+" sign before a number and needs to be converted to "-" sign.
Currently, I have to manually edit these cells or use the custom number format to change the value daily.
I am wondering if it would be possible to change the value of these numbers in the range?
Other note: it must only change the cells with numbers preceded with the "+"

I took your code from the comments and tried to correct the issue:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Sheet1');
const parsed = parseInt(sheet.getRange('C3:C330').getValue());
if (isNaN(parsed)) {
return 0;
}
return parsed * -100;
}
You need to pass the value of the range into the parseInt function. -199 in my comment was just an example value. Let me know if this makes more sense.

Related

VB.NET - Can't get Integer to work

I'm working with Windows Forms Application in Visual Studio 2015, using .NET Framework 4.5.2. So I'm making a simple program which includes a label to display a value. The label (called lblMoney) displays the currency (in this case, $) and then the value (e.g 350). Together it looks like $350.
Now, I made another form with a textbox called txtCash and a button called bApply. You enter any integer (e.g 350) into txtCash. When you press bApply, the number in txtCash will add to the number in lblMoney. So, if you had 5 in lblMoney, and you entered 350 in txtCash, lblMoney would display 355.
Here's my code to add to the number:
My.Forms.VeilSideCash.lblMoney.Text = cstrx + txtCash.Text.ToString
The form VeilSideCash is the form that holds lblMoney.
Here's the code for cstrx:
Dim cstrx = "$" & Val(My.Settings.Money.ToString)
The problem here is that, instead of overwriting to lblMoney, the new number is just added after the original number. So if lblMoney has 5 and you enter 350 into txtCash, lblMoney looks like $5350.
How would I go about overwriting with the new number (adding to) instead of replacing?
Any help would be appreciated. Feel free to edit incase I messed something up while explaining.
The problem with your code is the Option Strict setting for your project. You have it set to Off and this allows your code to freely treat strings as they were numbers and try to use them in mathematical operations.
But, when you use the + operator between two strings, it doesn't matter if, for a human being, the two strings represent a number, the compiler see them as strings (cstrx, txtCash.Text) and thinks that you want to use the concatenation operator defined for strings (the +). Yielding wrong (for you) results .
I really suggest you to not use the automatic conversions made by the compiler on your code, instead, when you need to do math operations, always convert your strings to numbers and do the math with variables of numeric type (You could also change the Option Strict to On, but you should be prepared to solve a lot of problems in your current code)
Instead, with a proper numeric approach, you get the text inside txtCash and try to check if your user has correctly typed a decimal value.
Dim cash As Decimal
if Not decimal.TryParse(txtCash.Text, cash) Then
MessageBox.Show("Invalid cash value")
Return
End if
Now get the text of lblMoney and convert it back to a decimal number alerting the compiler that there is a currency symbol in the text to convert
Dim current As Decimal
current = decimal.Parse(lblMoney.Text, NumberStyles.Currency, CultureInfo.CurrentCulture)
Now you have two numbers and the + operator does what you expect. It adds the two numbers together. Finally you could write back the result with a proper currency formatting
Dim result as Decimal
result = current + cash
lblMoney.Text = result.ToString("C")
You need to remove the "$" and convert to a number. I used a decimal so you can include cents if you want:
Dim sum As Decimal
sum = Val(cstrx.Replace("$","")) + Val(txtCash.Text)
My.Forms.VeilSideCash.lblMoney.Text = sum.ToString()
Dim cstrx = sum.ToString("C")
Note that I used the "C" to format the sum as currency. That automatically puts the $ on for you, or uses other currency symbols for other countries.
I'm not a big VB.net user, so my syntax may be slightly off.
When you use the + operator with string unexpected results can occur. In this case the string with a $ cannot be implicitly converted so you should explicit convert it
Once you convert your strings to a number type you can then use the + operator and they can be implicitly converted back to a string.
My.Forms.VeilSideCash.lblMoney.Text = decimal.Parse(cstrx, NumberStyles.Currency)
+ decimal.Parse(txtCash.Text ,NumberStyles.Currency)

Google Script Sheets API - default number format

It looks like google sheets is making the same mistake as Excel, by "thinking ahead" and converting the value "1.1.1" to 2001.01.01 when doing sheet.appendRow. I have tried to set the number format of the column in charge to "#" (which should be plain text) before inserting rows - but looks ineffective. On the other hand doing the same after inserts is also ineffective, as the content is already "date".
Adding ' before is working, but it is not what I need.
Is there any way to give a default format or to disable such automatic conversion (from google script)?
I have a cell in which a form deposits a variable number of values seperated by a comma such as: " 1, 2, 4, 6 " etc - when there are only three answers, Google "helps" me by converting the value into a date object. But it's supposed to be a list of choices...
It's not pretty, but I've managed a workaround by using .getDisplayValue instead of .getValue - it does change the cell value into a string, so if you need to do further manipulations that are dependent on the value being a number or something, obviously, this fails.
I overwrite the value for the problem cell in my array before passing it to .appendRow
//getting the values
var values = s.getRange(row,1,1,lastCol).getValues()[0];
//brute force crushing of problem value
values[5] = s.getRange(row,6).getDisplayValue();

UDF to return formatted number

Sometimes I like to display numbers along with text in the same cell. To do this, I custom format the cell to something like 0.00" test", e.g. a cell A1 with formula =PI(), but formatted with custom format 0.00" test" would return a displayed result of 3.14 test.
Crucially, the value of the cell is unchanged by the formatting - you can still do =A1 * 3 in another cell and get the result - since the value of A1 is still Pi, only it's display has changed.
For a UDF that returns a numerical value (in my case, Long, but it could be any number), is there a way of returning a cell such that it is displayed 1 way, but it's actual value (.Value2 in VBA I believe) is a number, not text.
I've tried Format( in VBA, but it returns a text string. I would just format my cell how I want it manually, but as you can see from the below code, the formatting is dependent on intermediate results (I'm trying to return the value formatted with the time the calculation took).
UDF_RESULT = Format(valueResult.Length, IIf(tElapsed < timeout, "0" & " """ & Round(tElapsed, 2) & "s""", "0"))
This would be easy to do with a Macro, but within a UDF it's harder. I could declare all of the intermediate values at a module level, then a Worksheet_Calculate() macro can access those values and apply the custom formatting, but a UDF-wrapped approach would be much better.
No.
You're confusing a cell's value with its number format. A UDF can compute a value, and the cell is free to format that value as needed.
So if a UDF returns a number, the cell's value is the result of that function - a number.
Just format the cell as needed. A function doesn't format anything.

How to avoid repeating myself in spreadsheet =INDEX(FILTER(), FILTER()) expression?

I have a spreadsheet formula in which I use exactly the same FILTER function twice inside an INDEX function. Is there any way to avoid repeating myself, and/or a simpler version of the expression?
The expression looks like this (separated into multiple lines for a tiny bit of extra clarity):
=INDEX(
FILTER($A$1:$P$1, ($A$1:$P$1 = "ANIM")+($A$1:$P$1 = "COMP")+($A$1:$P$1 = "SENT TO EDIT"),
NOT (ISBLANK(A2:P2))),
COLUMNS(
FILTER($A$1:$P$1, ($A$1:$P$1 = "ANIM")+($A$1:$P$1 = "COMP")+($A$1:$P$1 = "SENT TO EDIT"),
NOT (ISBLANK(A2:P2)))))`
What the expression does is return the heading of the rightmost non-blank column in the row, so long as the column is one of ANIM, COMP, or SENT TO EDIT.
See the formula in action in column Q of this Google Sheets.
Since the FILTER function is exactly the same both times, if I could use a variable, it could be re-written something like this:
range1 = FILTER(.....); INDEX(range1, COLUMNS(range1));
Is there any way to do something like that - or an equivalent - in order to avoid repeating my FILTER expression?
You have the right idea, the way to avoid repeating long subformulas is to move them out of the formula and call the result someway. On certain cases you could use a reference to the range that displays the result but for formulas that returns a dynamic array, a custom function could be a better alternative.
Example:
Let say that you move out
FILTER($A$1:$P$1, ($A$1:$P$1 = "ANIM")+($A$1:$P$1 = "COMP")+($A$1:$P$1 = "SENT TO EDIT"),
NOT (ISBLANK(A2:P2)))
to dry!A1 (don't forget to prepend it with =)
The following is just a "mcve". It assumes that te dry sheet only contains the above formula:
function headers(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets().getSheeyByName('dry');
return sheet.getDataRange().getValues();
}
Replace your original formula for the following:
=INDEX(headers(dry!A1:P1),COLUMNS(headers(dry!A1:P1))
Note: The use of dry!A1:P1 as arguments of headers() is to force it's recalculation every time that the result for the subformula changes.
See also: Is there a way to evaluate a formula that is stored in a cell?
You could try something like this:
=REGEXEXTRACT(JOIN("|",FILTER($A$1:$P$1, Regexmatch($A$1:$P$1,"ANIM|SENT TO EDIT|COMP"), NOT (ISBLANK(A2:P2)))),"([^|]+)$")
Using regular expressions is a way to handle arrays like a text.
What you are looking for is called a temporary variable, and last I checked, Google sheets doesn't support temporary variables (https://webapps.stackexchange.com/questions/71095/how-to-save-temporary-variables-in-google-sheets-formula). It would be nice if they did!

While loop not working as intended. Google script

I am very new at programming in Google Script, and need some guidance here.
I have a loop that is supposed to check the value of a range, then move down to the next row and set the new range's value as "next", which is then compared to "team".
If the condition is met then "team" is given the same value from the range that "next" was given, and "next" is given the value of the range below the current one.
The purpose is to find how many entries there are that meet conditions in a column, then my other parts of the code manipulate that data.
When the "team" value isn't the same as "next" (the value of the range below the current one), then the loop is supposed to stop, but doesn't. Code:
while (team = next) {
team = orange.getValue();
row ++;
range = col + row.toString();
orange = ordered.getRange(range);
next = orange.getValue();
entries ++;
};
I'm not familiar with Google Script either, but most languages require double equal sign for equality tests. From a cursory view I think Google Script uses the same syntax. Try doing this instead:
while (team == next)
Notice the double == to check for equality instead of single = to assign a variable.