【问题标题】:Custom function for Google Spreadsheet - handling the array passed from the spreadsheetGoogle 电子表格的自定义函数 - 处理从电子表格传递的数组
【发布时间】:2013-08-01 20:42:07
【问题描述】:

我正在尝试构建一个简单的脚本来使用 Google 电子表格。电子表格从 Google 表单中获取输入,因此电子表格中有一系列值,如下所示:

我的目标是编写一个脚本,在用户指定的范围内从每个表单输入中去除数字,然后将所有数字相加以提供一个分数。因此,例如,用户可以在单元格中输入=sumColumns(H2:K2),它会返回分数的总和(对于我发布的示例屏幕截图,它将返回3+3+0+39 的结果)。

这是我为此编写的代码:

function sumColumns(values) {
  var sum = 0;
  for(var i = 0; i <= values.length; i++){
    var input = values[0][i];
    var x = input.toString();
    var y = x.charAt(0);
    var num = parseInt(y);
    sum += num;
  }
  return sum;
}

问题在于它似乎只会将两个值相加。因此,当我将=sumColumns(H2:K2) 放入电子表格的单元格中时,它只返回6。此外,在第 3 行,如果我将其从 i &lt;= values.length 更改为 i &lt; values.length,它只会添加一个数字,因此我会得到 3。我的猜测是我误解了将 Google 电子表格值传递给函数的方式,但我完全无法使其工作。非常感谢任何帮助!

【问题讨论】:

    标签: javascript google-apps-script google-sheets google-forms custom-function


    【解决方案1】:

    糟糕 - 编辑并保存了问题,写了一个答案 - 忘记保存了。我让 Serge 打败了我!而且,像往常一样,Serge 的答案效果很好(使用整数值)。但你确实问过事情是如何运作的,所以你去吧。

    当你给自定义函数一个范围作为参数时,在这种情况下H2:K2,函数接收一个二维数组,相当于Range.getValues()的返回值。您可以通过(临时)更改您的函数以返回参数的 JSON 表示来轻松测试这一点:

    function sumColumns(values) {
      return JSON.stringify(values);   // For debugging, just return string showing values
      ...
    

    您将在包含=sumColumns(H2:K2) 的单元格中看到以下内容:

    [["3 (Rarely)","3 (Frequently)","0 (Never)","3 (Frequently)"]]
    

    这显示了一个由[ .. ] 包围的数组,其中还有另一个数组,也用方括号括起来,并且该数组有四个元素。如果我们将范围改为H2:K3,我们会得到这个(为清楚起见添加了空格):

    [
      ["3 (Rarely)","3 (Frequently)","0 (Never)","3 (Frequently)"],
      ["","","",""]
    ]
    

    既然您知道了这一点,就很容易理解为什么您的函数会给出它所做的结果。

    首先,for(var i = 0; i &lt;= values.length; i++) 使用了错误的数组边界进行循环,因为values.length 会告诉我们values 中有多少。在H2:K2 中,该长度为1。相反,我们需要遍历第一行 (values[0]) 中的列,以及其 4 单元格。

    对于这个循环,您想知道 &lt;&lt;= 的区别 - 我们确实需要使用 &lt;,因为它是基于 0 的索引,而 .length 返回元素的计数。所以我们最终得到:

    for (var i=0; i < values[0].length; i++){ ... }
    

    使用parseInt() 是一个不错的选择,并且适用于电子表格中的值。但是,可以通过确保首先去除任何 String 值的前导非数字值来改进它 - parseInt() 然后可以在字符串中找到一个 Integer。

    function sumColumns(values) {
      return JSON.stringify(values);   // For debugging, just return string showing values
      var sum = 0;
      for(var i = 0; i < values[0].length; i++){
        var input = new String(values[0][i])
                     .replace( /^\D+/g, '');    // Strip any leading non-digits
        sum += parseInt(input);
      }
      return sum;
    }
    

    【讨论】:

      【解决方案2】:

      我不擅长自定义函数,因为我从不使用它们,但似乎 values 并不是真正的数组...


      斜体评论:

      嗯,尴尬...我的第一个想法是它必须是一个二维数组,但我在测试中记录了 val[0],它返回了一个“未定义”错误...我一定是在那一刻......无论如何,这就是为什么我寻找一种将数据作为字符串处理并使用拆分和正则表达式的方法。 与 Mogsdad 的答案一样,您有一个答案以及随之而来的所有解释 ;-) 而且,与他一样,您也经常得到比我更好的答案。 (一个限制虽然(@Mogsdad)你对非整数值的评论也可以应用于你的代码......你只需用 parseInt() 去掉任何十进制值......:-) 也就是说,您的用例已得到很好的描述,并且在此示例的限制范围内,两个代码都应该按预期工作,Mogsdad 的代码更“学术”并且在编程上是正确的。

      评论结束。


      使用下面的这个技巧,它对任何输入范围(1 行或更多行和列)都可以正常工作:

      function sumCol(val) { // returns the sum of all numeric values in range
        var values = val.toString().split(',');
        var sum = 0;
        for(var n=0;n<values.length;++n){
          sum+=Number(values[n].replace(/[^0-9+.]/ig,''));
        }
        return sum;
      }
      

      我还更改了数字提取模式以使其更通用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-28
        • 1970-01-01
        • 2015-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多