I need to sum all the even values from my array, so here is an example of it:
Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => 1
[4] => 4
[5] => 6
[6] => 6
)
looking a way to sum all from same value:
Array
(
[1] => 4
[4] => 1
[6] => 2
)
Any ideas?
var buckets:Object = {};
var data:Array = [1, 1, 1, 1, 4, 6, 6];
for(var i=0; i<data.length; ++i) {
if(!buckets[data[i]]) {
buckets[data[i]] = 1;
} else {
buckets[data[i]]++;
}
}
trace(buckets);
Try this:
var sum:uint = 0; //Setting the sum value to 0;
for(var i:uint = 0; i < nameOfArray.length; i++){ //Loops trough the array
if(nameOfArray[i] % 2 == 0 ){ //If the number is an even number
sum+=nameOfArray[i]; //Add that even number to the sum variable
}
}
trace(sum) // Prints out the sum
You could create a map & loop through your array, adding the values into you're map. If you don't know what a map is, it is basically a collection type. It is created using a pair, using a unique key & a value associated with it. In your case, the unique key will be the number value in the array and the value will be the number of times it appears (frequency).
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 =>
I want to get the value of all the cells of rows. But not from all the rows, only rows having specific name in a specific column.
I attached a screenshot. I want to get all row values which "userID" is "user3". It means row 4 row 6 data.
I used following code.
function getByName(colName, row) {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var col = data[0].indexOf(colName);
if (col != -1) {
return data[row-1][col];
}
}
Above I getting only specific cell value in the user ID column. Not all data in the ROW.
function getAllrowData() {
var user3 = getByName("userID",2);
var values = user3.getDisplayValues()
Logger.log(values)
return values
}
getByname giving only cell value.
I want following result so I can display data in html, belongs to only "user 3" in the image. Help me to correct my code.
C 25 30 0 16 user3
E 28 36 6 19 user3
Get Data by Row Number and Column Name:
function getByName(user, colName = 'userID') {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
const hA = data.shift();
const idx = hA.reduce((a, h, i) => (a[h] = i, a), {});
let o = data.map(r => {
if (r[idx[colName]] == user) {
return r;
}
}).filter(r => r );
if (o && o.length > 0) {
return o;
}
}
Remove [col] from return data[row-1][col];
The above because sheet.getDataRange().getValues(); return an Array of Arrays of values. Using two indexes returns a cell value, using only the first index will return an Array having all the row values.
I am trying to set the value of a cell in a column when two other columns at an index match values. How can I set the value using an index? (<Edited)
for (let i = 0; i < assetId.length; i++) {
for (let p = 0; p < oldId.length; p++) {
if (assetId[i] !="" && oldId[p] !="") {
if (assetId[i] == oldId[p]) {
Logger.log('Old Match: ' + assetId[i])
//if match modify 4th column at row [i] to 'null'
d.getRange(i,3).setValue('null')
}
}
}
}
Based on if assetId[i] == oldId[p], I am trying to change column F of row [i] to 'null'
Edit (examples requested)
Column J is oldId and K is newId
EXPECTED OUTPUT: F4 should be null
Full code:
function replaceIds() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const r = ss.getSheetByName("Form Responses 1")
const d = ss.getSheetByName("Devices")
const oldId = r.getRange("J2:J").getValues().flat()
const newId = r.getRange("K2:K").getValues().flat()
const studentName = r.getRange("C2:C").getValues().flat()
const assetId = d.getRange("G3:G").getValues().flat()
const annotatedUser = d.getRange("E3:E").getValues().flat()
for (let i = 0; i < assetId.length; i++) {
for (let p = 0; p < oldId.length; p++) {
if (assetId[i] !="" && oldId[p] !="") {
if (assetId[i] == oldId[p]) {
Logger.log('Old Match: ' + assetId[i])
//if match modify 4th column at row [i] to 'null'
d.getRange(i,3).setValue('null')
}
}
}
//new asset ID loop
for (let r = 0; r < newId.length; r++) {
//Logger.log(oldId[p])
if (assetId[i] !="") {
if (newId[r] !="") {
//Logger.log('## not null ##')
if (assetId[i] == newId[r]) {
Logger.log('New Match: ' + assetId[i])
}
}
}
}
}
}
Issue:
Issue is that, using a nested for loop is not a good idea as you can't properly follow where the proper index is, and it will also needlessly reiterate on items that were already visited.
Solution:
Looping only on the assetId should suffice, then using indexOf as it will help you identify if a certain element (current assetId) belongs in an array (list of oldIds).
If assetId is found, indexOf will return a non-negative number (which is what index the element is found in the array).
Exclude empty assetIds due to how you get your data
Then you can remove the column of that same row, but since index starts at 0 and your data starts at 3rd row, we need to offset the getRange row so it would match the cell we want to delete properly.
Modifying your current solution, this is what the solution says above, and should work.
Script:
function replaceIds() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const r = ss.getSheetByName("Form Responses 1")
const d = ss.getSheetByName("Devices")
const oldId = r.getRange("J2:J").getValues().flat()
const newId = r.getRange("K2:K").getValues().flat()
const studentName = r.getRange("C2:C").getValues().flat()
const assetId = d.getRange("G3:G").getValues().flat()
const annotatedUser = d.getRange("E3:E").getValues().flat()
// loop your assetId
assetId.forEach(function(cell, index){
// if assetId is listed under oldId, remove annotated location of that row
// also, skip any rows where assetIds are blank
if(oldId.indexOf(cell) > -1 && cell != "")
// offset here is 3 since assetId starts at G3 and index starts at 0
// 3 - 0 = 3, which is the offset, and 6 is column F
d.getRange(index + 3, 6).setValue('');
});
}
Output:
This function will change the value in column1 if the value of col2 at that index is in column 10 on any line. you can change the indices as you desire.
function findDataBasedOnMatch() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const sr = 2;//data start row
const vs = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn()).getValues();
const col10 =vs.map(r => r[9]);//you pick the indices
vs.forEach((r,i) => {
if(~col10.indexOf(r[1])) {//you pick the indices
sh.getRange(i + sr, 1).setValue('');
}
});
}
If I select range the number 1 to 2 , the output will come in matrix format 2X2 as,
1st row =>1and2
2nd row =>2and1
(OR)
1st row =>2and1
2nd row =>1and2
If I select range the number 1 to 3 , the output will come in matrix format 3X3 as,
1 2 3,
2 3 1,
3 1 2
(OR)
2 1 3,
3 2 1,
1 3 2
whatever the output may come, But each cell value shouldn't come again in the same row and column.
If I select range the number 1 to 4 , the output will come in matrix 4X4 format as,
4 2 1 3,
1 4 3 2,
2 3 2 4,
3 1 4 1
I need to shuffle the range. I wish to clear this concept using php. Pls. anyone help.....
Since one answer is always known; [a, b, c] => [ [ a, b, c], [ b, c, a ], [ c, a, b ] ], basically a repeating array_shift.
$startValue = 1;
$endValue = 3;
$arr = [];
for($idx = $startValue; $idx < $endValue + 1; ++$idx)
array_push($arr, $idx);
$result = [ $arr ];
$row = $arr;
while(count($result) < count($arr)) {
array_push($row, array_shift($row));
array_push($result, $row);
}
print_r($result);
Result:
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[1] => Array
(
[0] => 2
[1] => 3
[2] => 1
)
[2] => Array
(
[0] => 3
[1] => 1
[2] => 2
)
)
Can this be refactored into one LINQ statement? I feel like it can be but can't wrap my head around it. The mishmash of extension methods and LINQ just looks ugly to me.
(db is a DataContext.)
void AddToSeries(Series series, DateTime date)
{
foreach (var date in db.Ad.Select(ad => ad.DateTime.Date).Distinct())
{
var phraseCount = (from pc in db.PhraseCount
where pc.DateTime.Date == date
select pc.Count).SingleOrDefault();
var adCount = db.Ad.Where(ad => ad.DateTime.Date == date).Count();
series.Add(new KeyValuePair<DateTime, double>(date, adCount));
}
}
First refactor to consistent style.
void AddToSeries(Series series, DateTime date)
{
var dates = db.Ad
.Select(ad => ad.DateTime.Date)
.Distinct();
foreach (DateTime date in dates)
{
var phraseCount = db.PhraseCount
.Where(pc => pc.DateTime.Date == date)
.Select(pc => pc.Count)
.SingleOrDefault();
var adCount = db.Ad
.Where(ad => ad.DateTime.Date == date)
.Count();
series.Add(new KeyValuePair<DateTime, double>(date, adCount));
}
}
Aha:
phraseCount is not used
key is a date, value is a count
multiple database trips is no fun
date parameter for this method is blocked by the foreach variable
Now we can refactor:
void AddToSeries(Series series, DateTime date)
{
var pairs = db.Ad
.GroupBy(ad => ad.DateTime.Date)
.Select(g => new {key = g.Key, theCount = g.Count()});
foreach (var x in pairs)
{
series.Add(new KeyValuePair<DateTime, double>(x.key, x.theCount));
}
}