使用Google Apps脚本,如何将一列中的值与其他列中的值进行比较?

时间:2019-03-07 06:27:38

标签: javascript algorithm google-apps-script google-sheets spreadsheet

因此,如果我有一个电子表格,人们可以在其中继续对歌曲进行排名(每首歌曲都有自己的行,每个用户都有自己的列),那么我该如何编写脚本来遍历每个用户列,然后比较各个用户的将每首歌曲的评级添加到输入列?目的是输出与输入列的排名最相似的列(理想情况下,这应该是一个迭代递归函数,其空间复杂度为O(1),时间复杂度为O(log(n))。 我想做一个产生公式的函数,该公式将像=FINDMOSTSIMILAR(<USER>)这样使用,该公式输出输出列中第一行的值,但是我不确定从哪里开始。我有一些JavaScript方面的经验,我知道apps-script基于JS,但是我不知道如何在apps-script中执行此功能。

谢谢!

电子表格:https://docs.google.com/spreadsheets/d/1ruDFa8jmC3okuMvE6n6XfHMU66dNYEfxgUdXl-CMzJo/edit?usp=sharing

1 个答案:

答案 0 :(得分:2)

我试图给你一个开始。转到工作表,点击工具>脚本编辑器。粘贴此代码。

要查找相似的用户,此代码的作用是在输入用户和任何其他用户之间计算每个歌曲收视率的差异并将其相加以产生一个值。对工作表中的每个用户执行此操作。然后找到差异的最小值并输出由用户产生该值的值。此逻辑在compare函数中分开,您可以根据需要进行更改。

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  // Or DocumentApp or FormApp.
  ui.createMenu('Find Similar User')
      .addItem('Similar User', 'showPrompt')
      .addToUi();
}

// this configuration is based on current sheet names and formatting
// if sheet names change, change needed here
// if track title and user columns change, change needed here
var config = {
  // sheet name: [ col of track title, col of 1st user, col of last user ]
  "UV6": [6, 9, 28],
  "Midnight Underground": [7, 11, 28],
  "Furious Fap February": [8, 12, 23],
  "March Masturbation Madness": [7, 11, 31]
};

function showPrompt() {
  var ui = SpreadsheetApp.getUi(); // Same variations.

  var result = ui.prompt(
    'Find similar user.',
      'Enter user name:',
      ui.ButtonSet.OK_CANCEL);

  // Process the user's response.
  var button = result.getSelectedButton();
  var text = result.getResponseText();
  if (button == ui.Button.OK) {
    // User clicked "OK".
    text = text.trim();
    if (!text) return;
    FINDMOSTSIMILAR(text);
  } else if (button == ui.Button.CANCEL) {

  } else if (button == ui.Button.CLOSE) {

  }
}

function FINDMOSTSIMILAR(username) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var aSheet = ss.getActiveSheet();
  var aSheetName = aSheet.getName();

  // get positions from config
  if (!config[aSheetName]) return;
  var userNamesColsStart = config[aSheetName][1];
  var userNamesColsSpan = config[aSheetName][2] - config[aSheetName][1] + 1;
  var titleColStart = config[aSheetName][0];

  // read user names
  var users = aSheet.getRange(1,userNamesColsStart,1,userNamesColsSpan).getValues()[0];
//  Logger.log(users);

  // read title col
  var tArr = aSheet.getRange(2,titleColStart,aSheet.getLastRow()-2,1).getValues();
//  Logger.log(tArr);

  // data structure
  var DS = {};
  users.forEach(function(h, i) {
    var obj = {};
    var colValues = aSheet.getRange(2,userNamesColsStart+i,aSheet.getLastRow()-2,1).getValues();
    tArr.forEach(function(v, i) {
      obj[i] = colValues[i][0];
    });
    DS[h] = obj;
  });
//  Logger.log(DS);

  var target = DS[username];
  delete DS[username];

  var results = [];

  Object.keys(DS).forEach(function(user) {
    var obj = {};
    obj.prop = username+'__'+user;
    obj.value = compare(target, DS[user]);
    results.push(obj);
  });

  // sort based on difference values
  results.sort(comp);
  Logger.log(results);

  // user with lowest difference is answer
  var similarUser = results[0].prop.split('__')[1];
  Logger.log(similarUser);

  try {
    ss.getActiveCell().setValue([similarUser]);
  } catch(e) {}

}

function comp(a, b) {
  if (a.value < b.value) return -1;
  else if (a.value > b.value) return 1;
  else return 0;
}

// this takes a difference of two users ratings for the same song
// accumulate all the differences for all songs into a single value
// change here how to compare 2 song ratings
function compare(target, user) {
  var v = 0;
  Object.keys(target).forEach(function(key, i) {
    v += Math.abs(target[key] - user[key]);
  });
  return v;
}