Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Google apps script 在保留格式的同时对Google工作表中的行进行自定义排序_Google Apps Script_Google Sheets - Fatal编程技术网

Google apps script 在保留格式的同时对Google工作表中的行进行自定义排序

Google apps script 在保留格式的同时对Google工作表中的行进行自定义排序,google-apps-script,google-sheets,Google Apps Script,Google Sheets,我试图找出一种方法,除了升序/降序之外,还可以按照特定的顺序对谷歌电子表格中的数据进行排序。我可以通过使用Range.getValues()获取一个2D数组,对其进行排序,然后使用Range.setValues()来实现这一点 但问题是,它只是复制数据,对数据进行排序,然后将数据粘贴到旧数据上。因此,如果A1高亮显示为红色,并且通过对范围值进行排序将数据移动到B2,那么B2不会高亮显示为红色,而A1中的任何内容都将高亮显示为红色 是否有任何方法可以对区域进行实际排序,并在格式和所有内容保持不变的

我试图找出一种方法,除了升序/降序之外,还可以按照特定的顺序对谷歌电子表格中的数据进行排序。我可以通过使用Range.getValues()获取一个2D数组,对其进行排序,然后使用Range.setValues()来实现这一点

但问题是,它只是复制数据,对数据进行排序,然后将数据粘贴到旧数据上。因此,如果A1高亮显示为红色,并且通过对范围值进行排序将数据移动到B2,那么B2不会高亮显示为红色,而A1中的任何内容都将高亮显示为红色


是否有任何方法可以对区域进行实际排序,并在格式和所有内容保持不变的情况下移动行。

强制对
区域进行任意排序的方法。排序是在区域中附加一个临时列,并使用它进行排序。可以动态插入列,然后删除列,以避免损坏正在排序的区域旁边的数据

下面是一个按内容长度对A2:A7进行排序的示例

function sortRangeByLength() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getRange("A2:A7");
  sheet.insertColumnAfter(range.getLastColumn());
  var keys = range.getValues().map(function(row) {
    return [row[0].length];
  });
  range.offset(0, range.getNumColumns(), range.getNumRows(), 1).setValues(keys);
  var extendedRange = range.offset(0, 0, range.getHeight(), range.getWidth() + 1);
  extendedRange.sort({"column": extendedRange.getWidth(), "ascending": true});
  range.offset(0, 1).clear();
  sheet.deleteColumn(extendedRange.getLastColumn());  
}
范围
extendedRange
是带有附加列的
range
,用于排序,然后删除。对要删除的列调用
clear
,可能看起来是多余的,但它可以防止不必要的格式溢出到右侧的列(插入范围右侧的列继承其格式)

对于某些排序,可能没有明显的键,只有一个比较函数。在这种情况下,可以通过比较函数计算键,如下所示:

function sortRangeByLength() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getRange("A2:A7");
  sheet.insertColumnAfter(range.getLastColumn());

  // begin computing the keys
  var indexed = range.getValues().map(function(row, i) {
    return {"index": i, "content": row};
  });
  indexed.sort(function(a, b) {
    return (a.content[0].length < b.content[0].length ? -1 : (a.content[0].length > b.content[0].length ? 1 : 0));
  });
  var keys = Array(indexed.length);
  for (i in indexed) {
    keys[indexed[i].index] = [i];
  }

  // proceed as before
  range.offset(0, range.getNumColumns(), range.getNumRows(), 1).setValues(keys);
  var extendedRange = range.offset(0, 0, range.getHeight(), range.getWidth() + 1);
  extendedRange.sort({"column": extendedRange.getWidth(), "ascending": true});
  range.offset(0, 1).clear();
  sheet.deleteColumn(extendedRange.getLastColumn());  
}
函数sortRangeByLength(){
var sheet=SpreadsheetApp.getActiveSheet();
var范围=sheet.getRange(“A2:A7”);
sheet.insertColumnAfter(range.getLastColumn());
//开始计算密钥
var index=range.getValues().map(函数(行,i){
返回{“索引”:i,“内容”:行};
});
索引.sort(函数(a,b){
返回(a.content[0]。长度b.content[0]。长度?1:0));
});
变量键=数组(索引的.length);
对于(索引中的i){
键[索引[i]。索引]=[i];
}
//照旧进行
偏移量(0,range.getNumColumns(),range.getNumRows(),1);
var extendedRange=range.offset(0,0,range.getHeight(),range.getWidth()+1);
排序({“列”:extendedRange.getWidth(),“升序”:true});
range.offset(0,1).clear();
sheet.deleteColumn(extendedRange.getLastColumn());
}

这种方法是标准的:创建一个“索引”数组,其中包含每行的数据和索引。根据您的算法对该数组进行排序。由此产生的索引排列显示了行的位置。需要将其反转为“按此升序排序”键列。这个反转是
keys[index[i]。index]=[i]

创建一个排序对象并将其传递给范围。你的研究()应该让你找到@tehhowch是的,唯一的例子是关于如何按升序或降序对列进行排序。正如我所提到的,我不想这样。下次在你的问题中更具体、更详细——多列排序(例如通过sortObject)不是简单的升序/降序排序(诚然,它仅限于一个组合),你在问题中没有提到
范围.sort
。我认为,对任意字段的数据(如长度)进行排序的唯一方法是以某种方式序列化所需的维度,使其可以按升序或降序排序,如sftp所示。感谢这些示例,似乎非常简单,并且完成了工作。我所做的唯一更改是
range.offset(0,range.getNumColumns(),range.getNumRows(),1).设置值(键)
。如果不指定列数/行数,偏移量将与原始范围相同,并且
为单列,则必须在单列范围上设置值。