So I have been working on a program that ask the user to input a values and when the user exits the code by entering -99 its suppose to return the total Value of all the numbers and the average but I'm stumped My values keep getting overided by the previous one... here is my code
{
var user_Input;<br>
var output_msg;<br>
var count;<br>
var highest;<br>
var value;<br>
var total;<br>
count = 0;
do
{
user_Input = get_integer("Enter a number To add To the List(Enter -99 to leave)",-99);
if (user_Input == (-99)){
continue}
count += 1;
value = 0;
value = value + user_Input;
average = value/count;
}
until(user_Input == (-99)){
count -=1;
user_Input = user_Input + 99;
output_msg=("#Numbers Entered: " + string(count) + "##Total value of numbers: " + string(highest) + "## Average:" + string(average));`
}
show_message(output_msg);
}
How Do I make it so it doesn't override the previous one?
This is because you are setting value equal to 0 every time the while loop is executed. Try setting
value = 0;
before you start the do until loop. Perhaps right after
count = 0;
like this:
count = 0;
value = 0;
do{
user_Input = get_integer("Enter a number To add To the List(Enter -99 to leave)",-99);
if (user_Input == (-99)){continue}
count += 1;
value = value + user_Input;
average = value/count;
}
Related
I have a sheet with 4 columns, as shown below:
1
Date
Item Name
Counter
Flag
3
Date 1
Item A
1
4
Date 1
Item B
1
5
Date 2
Item B
2
6
Date 3
Item A
2
1
7
Date 3
Item B
3
8
Date 4
Item A
1
9
Date 5
Item A
2
Currently, I'm using a countif function [=countif(B$2:B2,B2)] to count the number of times a specific item appears in the spreadsheet. However, I need to find a way to restart the counter if there is a 1 in column D. In this case, this would mean that the formula in row 8 column C would be [=COUNTIF(B$8:B8,B8)] and would continue counting until it finds another row with a 1 in column D (e.g., formula in column C row 9 would be =COUNTIF(B$8:B9,B9). It would also ideally check whether there is a prior row with a 1 in column D, not through the order of the sheet, but by checking that it's date is smaller (and yet the closest date with a 1 in column D).
I've written the following script, which sets the row with a 1 in column D to 0 and sets the countif for the starting rows correctly to [=countif(B$2:B2,B2)], but it sets any row after there is a row with a 1 in column D as the same formula, with the starting range at B$2.
function setCountifFormula() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
var data = sheet.getDataRange().getValues();
for (var i = 1; i < data.length; i++) { //iterate through each row
var colBValue = data[i][1]; //get columnB in i
var colAValue = data[i][0]; // get date in i
var colDValue = data[i][3]; // get flag in i
var closestRow = 1; // empty variable
if( colDValue == "1") { //if columnD = 1
sheet.getRange(i+1,3).setValue(0); // set columnC = 0
} else {
for (var j = 1; j < data.length; j++) { //iterate through other rows
if (data[j][1] === colBValue && data[j][3] === "1") { // if columnB in j = ColumnB in i, and flag in row j = 1
var dateToCompare = data[j][0]; //set datetoCompare = date in row j
closestRow = j;
if (dateToCompare < colAValue) {
var range = "B$" + (closestRow + 1) + ":B" + (i + 1);
var formula = "=COUNTIF(" + range + ",B" + (i + 1) + ")";
sheet.getRange(i + 1, 3).setFormula(formula);
} else {
var range = "B$2:B" + (i+1);
var formula = "=COUNTIF(" + range + ",B" + (i+1) + ")";
sheet.getRange(i+1, 3).setFormula(formula);
}
}
}
if (closestRow === 1) {
var range = "B$2:B" +(i+1);
var formula = "=COUNTIF("+range +",B"+(i+1)+")";
sheet.getRange(i+1,3).setFormula(formula);
}
}
}
}
I can post the spreadsheet if needs be. If there is a different way without using scripts or COUNTIF, it'd be appreciated. Thanks!
I'm much better at scripting than complex formulas so here is an example of how I would do it.
function myCountif() {
try {
let values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
values.shift(); // remove headers
let unique = values.map( row => row[1] );
unique = [...new Set(unique)];
let count = unique.map( row => 0 );
let counts = values.map( row => 0 );
values.forEach( (row,rIndex) => {
let cIndex = unique.findIndex( item => item === row[1] );
count[cIndex] = count[cIndex]+1;
counts[rIndex] = count[cIndex];
if( row[3] === 1 ) count[cIndex] = 0;
}
)
return counts;
}
catch(err) {
console.log(err);
}
}
Reference
Array.shift()
Array.map()
Set Object
Array.forEach()
Array.findIndex()
Arrow function =>
So in the project I want to do I have a google sheet with timestamps and names next to those timestamps in the spreadsheet. I am having trouble accounting for duplicates and giving the name multiple timestamps in another google sheet.
for(var i = 0; i < length; i++){//for loop 1
if(currentCell.isBlank()){//current cell is blank
daySheet.getRange(i+10, 2).setValue(fullName);//set name to first cell
daySheet.getRange(i+10,3).setValue(pI);
daySheet.getRange(i+10,day+3).setValue(1);
}else if(counter > 1 ){//the index of the duplicate in the sheet month
//if counter is > 1 then write duplicates
for(var t = 1; t <= sheetLength ; t++){//loop through sign in sheet
//current index i
if(signInLN == signInSheet.getRange(t+1,3).getValue()){
//if there is a match
daySheet.getRange(t+10,day+3).setValue(1);
//day is equal to the day I spliced from the timestamp
//at this point I am confused on how to get the second date that has the same
//name and add to the row with the original name.
//when i splice the timestamp based on the row of index i, with duplicates I get
//the day number from the first instance where the name is read
}
}
}//for loop 1
How can I get this to work with duplicates so I can account for the dates but make sure that if there are
any duplicates they will be added to the row of the original name
Google Sheet EX:
12/10/2020 test1
12/11/202 test2
12/15/2020 test1
Should be something like this:
name 10 11 12 13 14 15 16
test1 1 1
test2 1
//the one is to identify that the date is when the user signed in on the sheets.
Sample Spreadsheet:
Code snippet done with Apps Script, adapt it to your needs.
use Logger.log() in case you don't understand parts of code
It is done mainly with functional JavaScript
function main(){
var inputRange = "A2:B";
var sheet = SpreadsheetApp.getActive().getSheets()[0]
var input = sheet.getRange(inputRange).getValues(); //Read data into array
var minDate, maxDate;
var presentDates = input.map(function(row) {return row[0];}); //Turns input into an array of only the element 0 (the date)
minDate = presentDates.reduce(function(a,b) { return a<b?a:b}); //For each value, if its the smallest: keep; otherwise: skip;
maxDate = presentDates.reduce(function(a,b) { return a>b?a:b}); //Same as above, but largest.
var dates = [];
for (var currentDate = minDate; currentDate <= maxDate; currentDate.setDate(currentDate.getDate()+1)) {
dates.push(getFormattedDate(currentDate)); //Insert each unique date from minDate to maxDate (to leave no gaps)
}
var uniqueNames = input.map(function(row) {return row[1];}) //Turns input into an array of only the element at 1 (the names)
.filter(function (value, index, self) {return self.indexOf(value) === index;}); //Removes duplicates from the array (Remove the element if the first appearence of it on the array is not the current element's index)
var output = {}; //Temporary dictionary for easier counting later on.
for (var i=0; i< dates.length; i++) {
var dateKey = dates[i];
for (var userIndex = 0; userIndex <= uniqueNames.length; userIndex++) {
var mapKey = uniqueNames[userIndex]+dateKey; //Match each name with each date
input.map(function(row) {return row[1]+getFormattedDate(row[0])}) //Translate input into name + date (for easier filtering)
.filter(function (row) {return row === mapKey}) //Grab all instances where the same date as dateKey is present for the current name
.forEach(function(row){output[mapKey] = (output[mapKey]||0) + 1;}); //Count them.
}
}
var toInsert = []; //Array that will be outputted into sheets
var firstLine = ['names X Dates'].concat(dates); //Initialize with header (first element is hard-coded)
toInsert.push(firstLine); //Insert header line into output.
uniqueNames.forEach(function(name) {
var newLine = [name];
for (var i=0; i< dates.length; i++) { //For each name + date combination, insert the value from the output dictionary.
var currentDate = dates[i];
newLine.push(output[name+currentDate]||0);
}
toInsert.push(newLine); //Insert into the output.
});
sheet.getRange(1, 5, toInsert.length, toInsert[0].length).setValues(toInsert); //Write the output to the sheet
}
// Returns a date in the format MM/dd/YYYY
function getFormattedDate(date) {
var year = date.getFullYear();
var month = (1 + date.getMonth()).toString();
month = month.length > 1 ? month : '0' + month;
var day = date.getDate().toString();
day = day.length > 1 ? day : '0' + day;
return month + '/' + day + '/' + year;
}
Run script results:
I'm looking for a tip for a AS3 script, have no idea how to start there
Button, if clicked the function is executed, which outputs a predefined value as the cross sum of a number string.
Example:
Cross sum should be 10
By clicking on the button, the function generates the number 55 or 82 or 37 or 523, ie numbers with the cross sum 10
An alternative way using % (modulo) instead of a string. You could write that into one line like this:
while (sum != 0) { qsum += sum % 10; sum /= 10; }
The trick is that modulo will give us only the last digit of the longer number, then we divide by 10 to trim off that last number (from longer) and we re-read a newer ending digit of the long number.
Example:
Long num = 1234, so each trim gives, 4 then 3 then 2 then 1 and we'll sum them up each time.
usage:
myInt = cross_sum(50); //makes myInt hold answer result of function (where ExpectedValue input is 50).
and the supporting function...
function cross_sum( ExpectedValue: int ) : int
{
var rand :int = Math.floor(Math.random() * 100000000000)
var sum :int = Math.abs( rand );
var qsum :int = 0;
while (sum != 0)
{
qsum += sum % 10; //get last digit of sum...
sum /= 10; //trim down sum by 1 digit...
}
if ( qsum == ExpectedValue ) { return rand; } //# stop here and give back "rand" as answer result.
else { cross_sum( expectedValue ); } //# else if wrong, try again...
}
Got it now.....
the function calculates a number, with the crosssum 50
function berechnen() {
var rand = Math.floor(Math.random() * 100000000000)
var sum = String(rand)
var qsum = 0;
for (var i = 0; i < sum.length; i++) {
qsum += Number(sum.charAt(i));
}
if (qsum == 50) {
summe.text = String(sum);
} else {
berechnen()
}
}
I am making a game that when you click on the Monster your score gets +1. But when your score goes over 1000 I would like it like this 1,000 rather than 1000. I am not sure how to do this as I have not learnt much action script. I have embed number and punctuation into the font. Here is my code so far:
var score:Number = 0;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
Monster.addEventListener(TouchEvent.TOUCH_TAP, fl_TapHandler);
function fl_TapHandler(event:TouchEvent):void
{
score = score + 1;
Taps_txt.text = (score).toString();
}
Help will greatly appreciated.
You can do like that:
function affScore(n:Number, d:int):String {
return n.toFixed(d).replace(/(\d)(?=(\d{3})+\b)/g,'$1,');
}
trace(affScore(12345678, 0)); // 12,345,678
This may not be the most elegant approach, but I wrote a function that will return the string formatted with commas;
public function formatNum(str:String):String {
var strArray:Array = str.split("");
if (strArray.length >= 4) {
var count:uint = 0;
for (var i:uint = strArray.length; i > 0; i--) {
if (count == 3) {
strArray.splice(i, 0, ",");
count = 0;
}
count++;
}
return strArray.join("");
}
else {
return str;
}
}
I tested it on some pretty large numbers, and it seems to work just fine. There's no upper limit on the size of the number, so;
trace (formatNum("10000000000000000000"));
Will output:
10,000,000,000,000,000,000
So in your example, you could use it thusly;
Taps_txt.text = formatNum(String(score));
(This is casting the type implicitly rather than explicitly using toString();, but either method is fine. Casting just looks a little neater in function calls)
Use the NumberFormatter class:
import flash.globalization.NumberFormatter;
var nf:NumberFormatter = new NumberFormatter("en_US");
var numberString:String = nf.formatNumber(1234567.89);
trace("Formatted Number:" + numberString);
// Formatted Number:1,234,567.89
To show the score with comma, you can do like this : ( comments are inside the code )
var score:Number = 0;
var score_str:String;
var score_str_len:int;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
Monster.addEventListener(TouchEvent.TOUCH_TAP, fl_TapHandler);
function fl_TapHandler(event:TouchEvent):void
{
score = score + 1;
score_str = score.toString();
score_str_len = score_str.length;
// here you can use score > 999 instead of score_str_len > 3
Taps_txt.text =
score_str_len > 3
// example : 1780
// score_str_len = 4
// score_str.substr(0, 4 - 3) = 1 : get thousands
// score_str.substr(4 - 3) = 780 : get the rest of our number : hundreds, tens and units
// => 1 + ',' + 780 = 1,780 : concatenate thousands + comma + (hundreds, tens and units)
? score_str.substr(0, score_str_len-3) + ',' + score_str.substr(score_str_len-3)
: score_str
;
// gives :
// score == 300 => 300
// score == 1285 => 1,285
// score == 87903 => 87,903
}
EDIT :
To support numbers greater than 999.999, you can do like this :
function fl_TapHandler(event:MouseEvent):void
{
score = score + 1;
score_str = score.toString();
Taps_txt.text = add_commas(score_str);
}
function add_commas(nb_str:String):String {
var tmp_str:String = '';
nb_str = nb_str.split('').reverse().join('');
for(var i = 0; i < nb_str.length; i++){
if(i > 0 && i % 3 == 0) tmp_str += ',';
tmp_str += nb_str.charAt(i);
}
return tmp_str.split('').reverse().join('');
/*
gives :
1234 => 1,234
12345 => 12,345
123456 => 123,456
1234567 => 1,234,567
12345678 => 12,345,678
123456789 => 123,456,789
1234567890 => 1,234,567,890
*/
}
Hope that can help you.
i have to handle unique names and save it in db like -
If name already exists, find the smallest number you can append to the name to save it as a unique name.
For example:
If username Scott already exists, save as Scott(1). If Scott(1) already exists, save as Scott(2). Etc.
i am using c# and sql server 2010
any great ideas ?
figured that out - but appreciate improvements
var seprator = "scott";
var list = new List<string>();
list.Add("scott");
list.Add("scott(1)");
list.Add("scott Alex");
list.Add("scott (4)");
list.Add("scott(xxx)");
list.Add("scott(250)");
list.Add("scott(12s)");
list.Add("scott(123)x");
list.Add("Scott caps");
list.Add("Alex Scott caps");
list.Add("xxxscottmmm");
var numberList = new List<int>();
foreach (var v in list)
{
var parts = Regex.Split(v, seprator, RegexOptions.IgnoreCase);
if (parts.Length > 1) //(1) Alex (4) (xxx) (250) (12s) (123)x caps caps
{
var secondPart = parts[1].Trim();
if (secondPart.StartsWith("(") && secondPart.EndsWith(")")) // (1) (4) (xxx) (250) (12s)
{
var valuebetweenbraces = secondPart.Substring(1, secondPart.Length - 2); //1 4 xxx 250 12s
int number;
var isNumber = int.TryParse(valuebetweenbraces, out number);
if (isNumber)
{
numberList.Add(number);
}
}
}
}
int maxValue = 0;
if (numberList.Count > 0)
maxValue = numberList.Max() + 1;
else
maxValue = maxValue + 1;
Response.Write(seprator + "(" + maxValue + ")");