Übergeben Sie den Bereich in der benutzerdefinierten Funktion des Google Apps-Skripts ohne Verwendung der A1-Notation

10

Ich bin neu im Google Apps-Skript und möchte eine Funktion für eine Tabelle erstellen, die Zellwerte summiert, wenn die Zellen bestimmte Kriterien erfüllen, z. B. die Hintergrundfarbe. Darüber hinaus möchte ich den Bereich als Array übergeben und aus folgendem Grund keine A1-Notation verwenden .

Ich fand eine Funktion , die A1 - Notation verwendet hier . Das Problem ist, wenn ich es in einer bestimmten Zelle habe

=sumWhereBackgroundColorIs("white", "A1:A10")

und ich kopiere den Wert in die rechte benachbarte Zelle, das Ergebnis wird wieder sein

= sumWhereBackgroundColorIs ("weiß", "A1: A10" )

während ich gerne hätte

= sumWhereBackgroundColorIs ("weiß", "B1: B10" )

Ansonsten muss ich das Eingabeargument immer manuell ändern und ich möchte dies vermeiden, da ich diese Funktion ausgiebig nutzen muss.

Daher habe ich versucht, einen Bereich als Array von Werten mit zu übergeben

=sumIfBgColor(#ffffff, A1:A10)


function sumIfBgColor(color, range){
    var x = 0;
    for(var i = 0; i < range.length; i++){
      for(var j = 0; j < range[i].length; j++){

        var cell = getCell();

        if(cell.getBackgroundColor() == color)
          x += parseFloat(range[i][j]);
      }
    }
    return x;
}

aber ich weiß nicht, wie ich die Zelle (dh das Objekt vom Typ Range) von dem bekommen soll, was ich habe.

Ganswer
quelle
Dies ist ohne die Verwendung eines API-Aufrufs nicht möglich. In diesem Fall müssen Sie die verwenden A1 notation.
Jacob Jan Tuinstra
Ich hasse es, es zu sagen, aber das Skript, das Sie gefunden haben, ist nicht sehr effizient. Bei einigen Zeilen ist der Unterschied möglicherweise nicht signifikant. Wenn Sie jedoch mehr Zeilen haben, z. B. 100, ist der Unterschied in der Verarbeitungszeit sehr groß. Das von mir erstellte Skript ist 30x schneller, da es nur drei API-Aufrufe verwendet. Das gefundene Skript verwendet ca. 100 Zeilen. 300 API-Aufrufe. Siehe mein Beispiel. Die angegebenen Zahlen sind Millisekunden.
Jacob Jan Tuinstra
Dies kann hilfreich sein: webapps.stackexchange.com/a/58179/12075
Sanmai
1
Versuchen Sie Folgendes: = sumWhereBackgroundColorIs ("weiß", ADRESSE (REIHE (A1), SPALTE (A10), 4) & ":" & ADRESSE (REIHE (A10), SPALTE (A10), 4))
Roamer

Antworten:

8

Zu @ Jacobs Behauptung der Unmöglichkeit widerlege ich es so ... (aber danke für die verbesserte Geschwindigkeit)

mit:

=sumIfBgColor("#ffffff", A1:A10, COLUMN(A1), ROW(A1))

Mit den folgenden Funktionen können Sie tun, was Sie wollen.

/**
 * Sums cell values in a range if they have the given background color
 * 
 * @param  {String} color    Hex string of color eg ("#ffffff")
 * @param  {Array.Array} range    Values of the desired range
 * @param  {int} startcol The column of the range
 * @param  {int} startrow The first row of the range
 * 
 * @return {int}          Sum of all cell values matching the condition
 */
function sumIfBgColor(color, range, startcol, startrow){
  // convert from int to ALPHANUMERIC - thanks to 
  // Daniel at http://stackoverflow.com/a/3145054/2828136
  var col_id = String.fromCharCode(64 + startcol);
  var endrow = startrow + range.length - 1
  // build the range string, then get the background colours
  var range_string = col_id + startrow + ":" + col_id + endrow
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var getColors = ss.getRange(range_string).getBackgrounds();

  var x = 0;
  for(var i = 0; i < range.length; i++) {
    for(var j = 0; j < range[0].length; j++) {
      // Sometimes the cell background is eg 'white' rather than '#ffffff'.
      // I don't know why - I think it's a bug.
      // so we remove that inconsistency with colourNameToHex
      // courtesy of Greg at http://stackoverflow.com/a/1573141/2828136
      if(colourNameToHex(getColors[i][j].toString()) == color) {
        x += range[i][j];
      }
    }
  }
  return x;
}

/**
 * Takes a colour string and returns it to a hex string. If a non-matching string is
 * passed, it will return the argument as is - for this situation it means that a
 * hex string can be passed to it and be returned as is. This is not for production.
 * 
 * @param  {string} color    Must be either a colour name or hex string of color eg ("#ffffff")
 * 
 * @return {object|string}          hex string of color eg ("#ffffff") or the argument given.
 */
function colourNameToHex(colour)
{
    var colours = {"aliceblue":"#f0f8ff","antiquewhite":"#faebd7","aqua":"#00ffff","aquamarine":"#7fffd4","azure":"#f0ffff",
    "beige":"#f5f5dc","bisque":"#ffe4c4","black":"#000000","blanchedalmond":"#ffebcd","blue":"#0000ff","blueviolet":"#8a2be2","brown":"#a52a2a","burlywood":"#deb887",
    "cadetblue":"#5f9ea0","chartreuse":"#7fff00","chocolate":"#d2691e","coral":"#ff7f50","cornflowerblue":"#6495ed","cornsilk":"#fff8dc","crimson":"#dc143c","cyan":"#00ffff",
    "darkblue":"#00008b","darkcyan":"#008b8b","darkgoldenrod":"#b8860b","darkgray":"#a9a9a9","darkgreen":"#006400","darkkhaki":"#bdb76b","darkmagenta":"#8b008b","darkolivegreen":"#556b2f",
    "darkorange":"#ff8c00","darkorchid":"#9932cc","darkred":"#8b0000","darksalmon":"#e9967a","darkseagreen":"#8fbc8f","darkslateblue":"#483d8b","darkslategray":"#2f4f4f","darkturquoise":"#00ced1",
    "darkviolet":"#9400d3","deeppink":"#ff1493","deepskyblue":"#00bfff","dimgray":"#696969","dodgerblue":"#1e90ff",
    "firebrick":"#b22222","floralwhite":"#fffaf0","forestgreen":"#228b22","fuchsia":"#ff00ff",
    "gainsboro":"#dcdcdc","ghostwhite":"#f8f8ff","gold":"#ffd700","goldenrod":"#daa520","gray":"#808080","green":"#008000","greenyellow":"#adff2f",
    "honeydew":"#f0fff0","hotpink":"#ff69b4",
    "indianred ":"#cd5c5c","indigo ":"#4b0082","ivory":"#fffff0","khaki":"#f0e68c",
    "lavender":"#e6e6fa","lavenderblush":"#fff0f5","lawngreen":"#7cfc00","lemonchiffon":"#fffacd","lightblue":"#add8e6","lightcoral":"#f08080","lightcyan":"#e0ffff","lightgoldenrodyellow":"#fafad2",
    "lightgrey":"#d3d3d3","lightgreen":"#90ee90","lightpink":"#ffb6c1","lightsalmon":"#ffa07a","lightseagreen":"#20b2aa","lightskyblue":"#87cefa","lightslategray":"#778899","lightsteelblue":"#b0c4de",
    "lightyellow":"#ffffe0","lime":"#00ff00","limegreen":"#32cd32","linen":"#faf0e6",
    "magenta":"#ff00ff","maroon":"#800000","mediumaquamarine":"#66cdaa","mediumblue":"#0000cd","mediumorchid":"#ba55d3","mediumpurple":"#9370d8","mediumseagreen":"#3cb371","mediumslateblue":"#7b68ee",
    "mediumspringgreen":"#00fa9a","mediumturquoise":"#48d1cc","mediumvioletred":"#c71585","midnightblue":"#191970","mintcream":"#f5fffa","mistyrose":"#ffe4e1","moccasin":"#ffe4b5",
    "navajowhite":"#ffdead","navy":"#000080",
    "oldlace":"#fdf5e6","olive":"#808000","olivedrab":"#6b8e23","orange":"#ffa500","orangered":"#ff4500","orchid":"#da70d6",
    "palegoldenrod":"#eee8aa","palegreen":"#98fb98","paleturquoise":"#afeeee","palevioletred":"#d87093","papayawhip":"#ffefd5","peachpuff":"#ffdab9","peru":"#cd853f","pink":"#ffc0cb","plum":"#dda0dd","powderblue":"#b0e0e6","purple":"#800080",
    "red":"#ff0000","rosybrown":"#bc8f8f","royalblue":"#4169e1",
    "saddlebrown":"#8b4513","salmon":"#fa8072","sandybrown":"#f4a460","seagreen":"#2e8b57","seashell":"#fff5ee","sienna":"#a0522d","silver":"#c0c0c0","skyblue":"#87ceeb","slateblue":"#6a5acd","slategray":"#708090","snow":"#fffafa","springgreen":"#00ff7f","steelblue":"#4682b4",
    "tan":"#d2b48c","teal":"#008080","thistle":"#d8bfd8","tomato":"#ff6347","turquoise":"#40e0d0",
    "violet":"#ee82ee",
    "wheat":"#f5deb3","white":"#ffffff","whitesmoke":"#f5f5f5",
    "yellow":"#ffff00","yellowgreen":"#9acd32"};

    if (typeof colours[colour.toLowerCase()] != 'undefined')
        return colours[colour.toLowerCase()];

    return colour;
}
Tom Horwood
quelle
1
Einfach ausprobiert und es funktioniert. Sehr gut, diese Antwort auf Webanwendungen zu haben.
Jacob Jan Tuinstra
2
Ich teste diese Dinge, weißt du? ;-)
Tom Horwood
Danke pnuts - habe gerade meine alte Antwort durchgelesen und dachte, ein bisschen Farbe könnte helfen (ich denke, es wird aber nicht passieren). Tut mir leid, alle, die Antworten im Notizblockstil lesen müssen :-)
Tom Horwood
2

Referenz: http://igoogledrive.blogspot.com/2015/11/google-spreadsheet-sum-of-colored-cells.html

Anstatt Parameter als Zeichenfolge an die benutzerdefinierte Funktion zu übergeben, verwendet das folgende Skript die Eingabe als Bereich:

/**
* @param {string} color String as background color to be searched for in sumRange
* @param {range} sumRange Range to be evaluated
* @return {number}
* @customfunction
*/

function sumColoredCells(color,sumRange) {
  var activeRange = SpreadsheetApp.getActiveRange();
  var activeSheet = activeRange.getSheet();
  var formula = activeRange.getFormula();
  var rangeA1Notation = formula.match(/\,(.*)\)/).pop();
  var range = activeSheet.getRange(rangeA1Notation);
  var bg = range.getBackgrounds();
  var values = range.getValues();
  var total = 0;

  for(var i=0;i<bg.length;i++)
    for(var j=0;j<bg[0].length;j++)
      if( bg[i][j] == color )
        total=total+(values[i][j]*1);
  return total;
};

Schauen Sie sich den folgenden Screenshot an:

Geben Sie hier die Bildbeschreibung ein

Kishan
quelle
1

Das folgende kleine Skript reicht aus.

Code

function sumIfBgColor(color, range){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var getColors = ss.getRange(range).getBackgrounds();
  var getValues = ss.getRange(range).getValues(), x = 0;
  for(var i = 0; i < getValues.length; i++) {
    for(var j = 0; j < getValues[0].length; j++) {
      if(getColors[i][j].toString() == color) {
        x += getValues[i][j];
      }
    }
  }
  return x;
}

Erklärt

Zunächst wird die aktive Tabelle ermittelt. Dann werden sowohl die Werte als auch die Farben basierend auf dem Bereich abgerufen. Die Werte werden verwendet, um die Farben und letztendlich die Summierung zu durchlaufen.

Verwendungszweck

Geben Sie hier die Bildbeschreibung ein

Beispiel

Ich habe eine Beispieldatei für Sie erstellt: Summe basierend auf Hintergrund

Jacob Jan Tuinstra
quelle
1
Diese Funktion funktioniert, aber Sie müssen sie mit A1-Notation aufrufen, dh in eine Zelle schreiben = sumIfBgColor (#ffffff, "A1: A10"). Dies entspricht nicht den Anforderungen, die ich oben geschrieben habe, nämlich beim Kopieren und Einfügen der Formel zwischen Zellen Ich muss den Inhalt manuell bearbeiten
Ganswer
@ganswer In meinem Kommentar zu Ihrer Frage habe ich bereits erwähnt, dass dies nicht möglich ist. Der Code, den Sie haben, sollte nicht mit oder ohne A1-Notation funktionieren. Deshalb habe ich ein Skript geschrieben, das dies tut.
Jacob Jan Tuinstra
Entschuldigung, ich habe Ihren Kommentar nicht gelesen. So schlechte Nachrichten! Es gibt also keine Möglichkeit. Ich kann die A1-Notation nicht verwenden. Ich muss das Layout meiner Tabelle vollständig ändern. danke
Ganswer
@ganswer Fanden Sie meine Antwort jedoch hilfreich?
Jacob Jan Tuinstra
1
Es ist eine gute Option, aber ich hatte bereits eine ähnliche Funktion, die mit der A1-Notation funktioniert. Bitte ändern Sie Ihre Antwort, einschließlich eines Kommentars oben, der besagt, dass das, wonach ich suche, nicht möglich ist, damit ich Ihre Antwort als Lösung akzeptieren kann
Ganswer