Przekaż zakres w niestandardowej funkcji skryptowej Google Apps bez użycia notacji A1

10

Jestem nowy w skrypcie Google Apps i chciałbym utworzyć funkcję dla arkusza kalkulacyjnego, który sumuje wartości komórek, gdy komórki spełniają określone kryteria, takie jak kolor tła. Ponadto chciałbym przekazać zakres jako tablicę i nie używać notacji A1 z następującego powodu.

Znalazłem funkcję, która używa notacji A1 tutaj . Problem polega na tym, że kiedy mam go w danej komórce

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

i kopiuję wartość do prawej sąsiedniej komórki, wynik będzie ponownie

= sumWhereBackgroundColorIs („biały”, „A1: A10” )

podczas gdy chciałbym mieć

= sumWhereBackgroundColorIs („biały”, „B1: B10” )

w przeciwnym razie zawsze muszę ręcznie modyfikować argument wejściowy i chcę tego uniknąć, ponieważ muszę intensywnie korzystać z tej funkcji.

Dlatego próbowałem, przekazując zakres jako tablicę wartości za pomocą

=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;
}

ale nie wiem, jak uzyskać komórkę (tj. obiekt typu Range), zaczynając od tego, co mam.

Ganswer
źródło
Nie jest to możliwe bez użycia wywołania API. Jeśli tak się stanie, musisz użyć A1 notation.
Jacob Jan Tuinstra
Nienawidzę tego mówić, ale skrypt, który znalazłeś, nie jest zbyt wydajny. W kilku wierszach różnica może nie być znacząca, ale jeśli masz więcej wierszy, powiedzmy 100, różnica w czasie przetwarzania jest ogromna. Skrypt, który przygotowałem, jest 30 razy szybszy, ponieważ wykorzystuje tylko trzy wywołania API. Znaleziony skrypt używa dla 100 wierszy, ok. 300 wywołań API. Zobacz mój przykład. Podane liczby są milisekundami.
Jacob Jan Tuinstra
Może to być pomocne: webapps.stackexchange.com/a/58179/12075
sanmai
1
spróbuj użyć tego: = sumWhereBackgroundColorIs („biały”, ADRES (WIERSZ (A1), KOLUMNA (A10), 4) i „:” i ADRES (WIERSZ (A10), KOLUMNA (A10), 4))
roamer

Odpowiedzi:

8

Na twierdzenie @ Jacoba o niemożliwości, obalam to w ten sposób ... (ale dziękuję za lepszą prędkość)

za pomocą:

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

z następującymi funkcjami zrobi to, co chcesz.

/**
 * 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
źródło
1
Po prostu spróbowałem i działa. Bardzo dobrze jest mieć tę odpowiedź w aplikacjach internetowych.
Jacob Jan Tuinstra
2
Wiesz, testuję te rzeczy. ;-)
Tom Horwood
Dzięki, orzechy - właśnie przeczytałem moją starą odpowiedź i pomyślałem, że trochę koloru może pomóc (ale chyba tak się nie stanie). Przepraszamy wszystkich, którzy muszą czytać odpowiedzi w stylu notatnika :-)
Tom Horwood
2

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

Zamiast przekazywania parametrów jako ciągu do funkcji niestandardowej, następujący skrypt przyjmuje dane wejściowe jako zakres:

/**
* @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;
};

Spójrz na następujący zrzut ekranu:

wprowadź opis zdjęcia tutaj

Kishan
źródło
1

Poniższy mały skrypt załatwi sprawę.

Kod

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;
}

Wyjaśnione

Najpierw określany jest aktywny arkusz kalkulacyjny. Następnie pobierane są zarówno wartości, jak i kolory oparte na zakresie. Wartości zostaną wykorzystane do iteracji kolorów i ostatecznie podsumowania.

Stosowanie

wprowadź opis zdjęcia tutaj

Przykład

Stworzyłem dla Ciebie przykładowy plik: Suma na podstawie tła

Jacob Jan Tuinstra
źródło
1
ta funkcja działa, ale musisz ją wywołać za pomocą notacji A1, tj. zapis na komórce = sumIfBgColor (#ffffff, „A1: A10”). To nie pasuje do wymagań, które napisałem powyżej, a mianowicie podczas kopiowania i wklejania formuły między komórkami Będę musiał ręcznie edytować treść
Ganswer
@ganswer W moim komentarzu do twojego pytania wspomniałem już, że nie jest to możliwe. Kod, który nie powinien był działać z notacją A1 lub bez niej. Dlatego napisałem skrypt, który to robi.
Jacob Jan Tuinstra
przepraszam, nie przeczytałem twojego komentarza. Tak złe wieści! Więc nie ma mowy ... Nie mogę używać notacji A1, będę musiał całkowicie zmienić układ mojego arkusza kalkulacyjnego. dzięki
Ganswer 10.10.2013
@ganswer Czy moja odpowiedź była dla Ciebie przydatna?
Jacob Jan Tuinstra
1
jest to dobra opcja, ale miałem już podobną funkcję, która działa z notacją A1. Zmodyfikuj swoją odpowiedź, w tym u góry komentarz mówiący, że to, czego szukam, nie jest możliwe, abym mógł przyjąć twoją odpowiedź jako rozwiązanie
Ganswer,