Google Apps脚本-如何编写代码以对数据列进行排名

时间:2019-03-04 22:59:32

标签: function google-apps-script google-sheets rank

我正在使用Google表单收集数据,以供教师确定有资格使用Title 1服务的学生使用。表单将数据提供给Google表格,我想自动按类别对分数求和,然后对每个类别进行排名。我有这段代码可将摘要从一列复制到另一列,但是随后我需要对列进行排名,这就是我遇到的问题。有人可以帮助我了解如何对数据进行排名吗?我认为我可能需要一个for循环-但我被卡住了。谢谢

function CopyRankData() 
{
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var SourceSheet=spreadSheet.getSheetByName('Ranking')
  var srcRange = SourceSheet.getRange('D1:D31');
  var destSheet = spreadSheet.getSheetByName('Ranking');
  var destRange = destSheet.getRange('I1:I31');
  srcRange.copyTo(destRange);
  --Need to Rank the column ---[Link to spreadsheet][1]
}

1 个答案:

答案 0 :(得分:0)

以下是一个非常简单的实用程序,可以正确模拟RANK公式(包括升序和降序排名)。如果您需要按范围的另一列对其进行排序或使用another comparator,则很容易更改并使其更通用。

您需要做的是根据某些条件对目标列值的副本进行排序,获取结果索引,然后将其递增1,因为数组索引基于0

/**
 * @summary ranks a range by first column
 * @param {number[][]} range
 * @param {(1|0)} [ascending]
 * @return {number[][]}
 * @customfunction
 */
const rankRange = (values, ascending = 0) => {

    try {

        const rows = values.map(v => v).sort((a, b) => {
            const aParsed = parseFloat(a[0]);
            const bParsed = parseFloat(b[0]);
            return ascending ?
                aParsed - bParsed :
                bParsed - aParsed;
        });

        return values.map((row) => {
            return [rows.findIndex(r => r[0] === row[0]) + 1];
        });

    } catch (error) {
        console.warn(`failed to rank column: ${error}`);
        return [[]];
    }
};

请确保项目中的V8 runtime is enabled能够正常运行(或在使用前将其转换为ES5语法)。


性能说明-优先使用map(v => v)来复制浅值。如果您希望项目数量很高,请使用slice()(由于TheMaster的评论,我决定研究性能下降的原因)。运行下面的交互式代码片段以查看区别:

const rng = document.querySelector("input[type=range]");

const arr = [];

const bench = (func, lbl) => {
  console.time(lbl);
  func();
  console.timeEnd(lbl);
}

rng.addEventListener("change", () => {
  const {
    value
  } = rng;

  const toAdd = new Array(+value).fill(42);

  arr.length = 0;
  arr.push( ...toAdd );

  bench(() => arr.slice(), "slice");
  bench(() => arr.map(v => v), "map");
});
.rng {
  width: 100%
}
<input class="rng" type="range" min="1" max="1e5" step="1">