I am facing a problem in the following script. I am not much into scripting at all and this is not my script also but here am getting the result which is grouping the values( For Example if i have a value A in three cells it should return the value as 3 instead it is returning AAA. Can someone help me out to count the values and return it
Thanks in Advance,
Here is the script :
function sumBackgroundColors(rangeString, color) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var sumRange = s.getRange(rangeString);
//var sum = 0;
var openCount = 0;
var sumRangeBackground = sumRange.getBackgroundColors();
var sumRangeValues = sumRange.getValues();
for(var row = 0; row < sumRangeBackground.length; row++ ) {
for(var col = 0; col < sumRangeBackground[0].length; col++ ) {
if( sumRangeValues[row][col]=="LG M"&& sumRangeBackground[row][col] == color ) {
openCount = openCount + sumRangeValues[row][col];
//if(sumRangeBackground[row][col] == color && sumRangeValues[row][col] == 1 ) {
// sum = sum + parseFloat(sumRangeValues[row][col]);
}
}
}
return openCount;
//return sum;
}
Here is a function which will take the value to be searched as argument. Rest of the things have been explained in comment lines.
function searchCount(value){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
//Get the whole data from activesheet in a 2D array
var data = sheet.getDataRange().getValues();
//Initialize counter
var count = 0;
//Iterate through the array
for(var i in data){
for(var j in data[i]){
// if a match found, increament the counter
if(value.toString == data[i][j]){
count++;
}
}
}
// return the count value
return count;
}
your problem could be due to openCount = openCount + sumRangeValues[row][col];
According to your example sumRangeValues[row][col] isn't an int. int + not an int = ??? if you want to keep a count of things you probably want openCount++ to replace that line instead, which is just a shortcut to openCount = openCount + 1;
Even if sumRangeValues[row][col] was an int, that line still wouldn't be what you're looking for. If you're searching for all the 3s in your spreadsheet your code would find your first 3, and then that line would execute 0 = 0 + 3 congrats, you just found 3 threes. You would continue to add three every time you found a three.
Waqar's code is essentially your code (amazingly simplified, but it iterates the same way) except he doesn't check color and he uses ++ instead of that line.
Related
I have a table with cells that contain numbers styled with fonts of different colors. I would like to sum all cell values of a certain color and output that sum into a separate cell. How can I do that?
Try (B1 contains a checkbox)
=sumColor(A:A,B1)
put the formula in a range with the same color as the data to be added
add a check box to allow you updating the value when colors will be changed
the formula can be located in another sheet
with this custom function
function sumColor(range) {
var r = SpreadsheetApp.getActiveRange();
var color = r.getFontColors();
var total = 0;
var addresses = r.getFormula().match(/(?<=\().*(?=\))/g)[0].split(/[;|,]/)
for (var i = 0; i < addresses.length - 1 ; i++) {
try {
var sh = SpreadsheetApp.getSheetByName(addresses[i].split('!')[0].replace("'", ""));
var address = addresses[i].split('!')[1].trim();
}
catch (e) {
var sh = SpreadsheetApp.getActiveSheet();
var address = addresses[i].trim()
}
var colors = sh.getRange(address).getFontColors();
var values = sh.getRange(address).getValues();
for (var j = 0; j < colors.length; j++)
for (var k = 0; k < colors[i].length; k++)
if (colors[j][k] == color)
if ((typeof values[j][k]) == 'number')
total += values[j][k];
}
return total;
};
I need to take a sheet maintained by someone else and do the following (so that I can export to a csv):
unmerge all cells
fill values down
merged cells are in multiple columns, so I need to iterate over a range
It's too much to do it by hand, and it will need done periodically. My javascript and google sheets object model knowledge approximate zero, but I know it's possible because I could do it in VBA. I searched but can only find programmatic answers for VBA/Excel.
How can I do this efficiently in Google Sheets?
You can use the breakapart() class to do this. I am assuming that the merged range is not static and has multiple occurrences. This script will unmerge all merged ranges in the active sheet.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).breakApart();
}
Adapted from #lreeder's answer
The following breaks and fill blank with above on the selected range:
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('BreakAndFill')
.addItem('Break Fill Blank Cells', 'menuItem1')
.addToUi();
}
function menuItem1() {
BreakandfillBlankWithAbove()
}
//Breaks range
//Iterates over the range from top to bottom
//and left to right, and fills blank cells
//with the value right above them.
function BreakandfillBlankWithAbove() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveRange();
Logger.log('Range height is: ' + range.getHeight());
var values = range.getValues();
range.breakApart();
var width = values[0].length;
var height = values.length;
Logger.log('Width is ' + width);
Logger.log('Height is ' + height);
for (var i = 0; i < width; i++) {
var lastVal = '';
for(var j = 0; j < height; j++) {
var currValue = values[j][i];
var dataType = typeof(currValue);
//Empty string check returns true if dataType
//is a number, and value is zero. In that case
//we don't want to overwrite the zero, so only
//check emptyString for string types.
if(currValue === undefined ||
(dataType === 'string' && currValue == '')
) {
//getCell parameters are relative to the current range
//and ones based
var cell = range.getCell(j+1, i+1);
cell.setValue(lastVal);
}
else {
lastVal = currValue;
}
}
}
SpreadsheetApp.flush();
}
I want to accomplish something like this:
I have a sort of "Relational" Spreadsheet, and I want rows to be colored according.
I manually choosing a unique color for each Category on the "Categories" Sheet or generating a unique color based on the string content, either would work for my use case.
Not the best solution but it works
function onEdit(e) {
if(e){
var ss = e.source.getActiveSheet();
var range = e.source.getActiveRange();
var r1 = range.getRow();
var c1 = range.getColumn();
var rowsCount = range.getNumRows();
for(var i=0; i<rowsCount; i++){
var row = ss.getRange(r1+i,1,1,ss.getMaxColumns());
updateRow(row, ss);
}
}
}
function updateRow(row, ss){
if (ss.getName() == "Entries") { // This is the sheet name
var cell = row.getCell(1,1);
var firstCellValue = cell.getValue();
if(firstCellValue){
cell.setBackgroundColor(stringToColor(firstCellValue));
}
else{
cell.setBackgroundColor(null);
}
}
}
function stringToColor(str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
var colour = '#';
for (var i = 0; i < 3; i++) {
var value = (hash >> (i * 8)) & 0xFF;
colour += ('00' + value.toString(16)).substr(-2);
}
return colour;
}
Based on this answer
in conditional formatting select the range you want to apply colors, select color, choose Text is exactly and set value:
I am trying to count the values in a cell based on the background color. Someone I got some help while online search I am not getting the complete solution. Does anyone help me out with this prob. I have sample code script which I got from the online search.
Also the script which am pasting here is grouping the values( For Example if i have a value A in three cells it should return the value as 3 instead it is returning AAA. Can someone help me out with the script to count the values and return it based on the background color
Thanks in Advance,
Here is the script:
function sumBackgroundColors(rangeString, color) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var sumRange = s.getRange(rangeString);
var sum = 0;
var sumRangeBackground = sumRange.getBackgroundColors();
var sumRangeValues = sumRange.getValues();
for(var row = 0; row < sumRangeBackground.length; row++ ) {
for(var col = 0; col < sumRangeBackground[0].length; col++ ) {
if( sumRangeValues[row][col]=="LG M"&& sumRangeBackground[row][col] == color ) {
sum = sum + parseFloat(sumRangeValues[row][col]);
}
}
}
return sum;
}
I recommend you to not use a custom function to do this because of its caching feature (explanation here).
function countBackgroundColors() {
var rangeString = "A1:A100";
var color = "green";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var range = s.getRange(rangeString);
var count = 0;
var rangeColors = range.getBackgroundColors();
for( var i in rangeColors )
for( var j in rangeColors[i] )
if( rangeColors[i][j] == color )
++count;
return count;
}
Here is my problem.
I'm doing a little weather web app in flash.
So i read an xml feed and copose an array of data from it.
my xml is like this
<xml>
<prevision>
<date>22</date>
<hour>5</hour>
<temperature>40</temperature>
</prevision>
<prevision>
<date>22</date>
<hour>10</hour>
<temperature>44</temperature>
</prevision>
<prevision>
<date>22</date>
<hour>14</hour>
<temperature>45</temperature>
</prevision>
<prevision>
<date>22</date>
<hour>20</hour>
<temperature>37</temperature>
</prevision>
</xml>
So here is what i'm doing with my Actionscript 2
//**************************************
// Here i'm getting the current hour
var mytime = new Date();
var currenthour = mytime.getHours();
//*************************************
// Here i'm getting my XML
var myhour:Array = new Array();
var myxml:XML = new XML();
myxml.ignoreWhite = true;
myxml.onLoad = function(success)
{
dataextractor = myxml.firstChild.childNodes;
for (var j = 0; j < dataextractor.length; j++)
{
myhour.push(dataextractor[j].childNodes[1].firstChild.nodeValue);
}
// Doing this
trace(mydate);
}
// Will return this
// 5 , 10, 14 , 20
Now what i would like to do is to find and trace the entry in mydate array which have a a value that approach the most to "currenthour" variable (which is my current time i'm getting upper).
For exemple if currenthour = 11
In the case that i have myhour array equal to 5 , 10 , 14 , 20
The best match will be myhour[1]
Can someone help to do so?
myhour Array don't have a fixed number of entries.
Sometime it can be 5, 10, 14 and other time just 14,20 etc
Thanks a lot,
I'm not sure, if I got your idea. Do you need to find the nearest number to currenthour from myhour array?
That's it:
var minDiff : int = 12;
var diff : int;
var index : int = 0;
for (var i : int = 0; i < myhour.length; i++)
{
diff = Math.abs(myhour[i] - currenthour);
if (diff > 12)
diff = 24 - diff;
if (diff < minDiff)
{
minDiff = diff;
index = i;
}
}
myhour[index] is the result. Hope, I got an idea.
Imagine your numbers on a line, from 0 to 24.
Using a variable to keep track of the smallest distance between the current hours and each hour in your XML, you can find the index of the node you're looking for:
import mx.xpath.XPathAPI;
var myxml:XML = new XML();
myxml.ignoreWhite = true;
myxml.onLoad = function(loaded:Boolean) {
if (loaded) {
var hoursMin:Number = 24;
var hoursNow:Number = new Date().getUTCHours();
var hourID:Number;
var hours:Array = XPathAPI.selectNodeList(this.firstChild, "xml/prevision/hour");
var hoursNum:Number = hours.length;
for(var i:Number = 0 ; i < hoursNum; i++){
var hoursDiff:Number = Math.abs(hoursNow - parseInt(hours[i].firstChild));//look for the 'shortest distance' within 24 numbers
if(hoursDiff < hoursMin){//found the smallest current value
hoursMin = hoursDiff;//update the minimum
hourID = i;//store the node ID
}
}
trace(this.firstChild.childNodes[hourID]);//access the closest node in time
} else {
trace("XML Load Error!!");
}
}
myxml.load("feed.xml");
Here's the same thing without XPath, although I find accessing nodes a bit harder this way:
var myxml:XML = new XML();
myxml.ignoreWhite = true;
myxml.onLoad = function(loaded:Boolean) {
if (loaded) {
var hoursMin:Number = 24;
var hoursNow:Number = new Date().getUTCHours();
var hourID:Number;
var hoursNum:Number = this.firstChild.childNodes.length;
for(var i:Number = 0 ; i < hoursNum; i++){
var hoursDiff:Number = Math.abs(hoursNow - parseInt(this.firstChild.childNodes[i].childNodes[1].firstChild));//look for the 'shortest distance' within 24 numbers
if(hoursDiff < hoursMin){//found the smallest current value
hoursMin = hoursDiff;//update the minimum
hourID = i;//store the node ID
}
}
trace(this.firstChild.childNodes[hourID]);//access the closest node in time
} else {
trace("XML Load Error!!");
}
}
myxml.load("feed.xml");
HTH