【问题标题】:Remove duplicated rows in Google Sheets ignoring the order of cells删除 Google 表格中的重复行,忽略单元格的顺序
【发布时间】:2016-09-14 22:20:03
【问题描述】:

我有一个包含许多“重复”行的电子表格。我不想手动删除它们,因为我有数千行。在我的特定情况下,行可能不是精确重复,因为我不关心行中单元格的顺序。这是一个例子:

A   B
dog cat
apple orange
red blue
cat dog

dog catcat dog 在我的情况下是重复的。所以,我想保留其中之一。不管是第一个还是最后一个。

我知道我需要某种与顺序无关的行比较。如何使用电子表格公式或 Google Apps 脚本来完成这项工作?

附:我的实际数据有 7 列,而不是 2 列作为我的示例。 (A到G)

【问题讨论】:

  • 水平排序;然后使用Remove Duplicates
  • @RonRosenfeld 我试过了,但找不到任何水平排序的方法,除非我一个一个地做
  • 这个问题的标签很奇怪。

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


【解决方案1】:

SpencerMaxOliver 的答案都使用电子表格公式返回过滤后的数组。它们的优点是可以在将新行添加到源数据时自动重新计算。

但是,您专门询问了有关删除行的问题,而这些答案都没有。为此,您必须使用脚本,因为公式不会从电子表格中删除源数据。

这个 sn-p 包含一个完整的脚本,包括一个菜单驱动的用户界面,它将为当前工作表调用 delSimilarRows() 函数。它被编写为包含电子表格的脚本,但可以轻松转换为附加组件。

/**
 * @OnlyCurrentDoc  Limits the script to only accessing the current spreadsheet.
 */

/**
 * Adds a custom menu
 *
 * @param {Object} e The event parameter for a simple onOpen trigger.
 */
function onOpen(e) {
  SpreadsheetApp.getUi()
      .createMenu('Custom')
      .addItem('Delete similar rows', 'delSimRowsGUI')
      .addToUi();
}


/**
 * Prompt user for confirmation before proceeding with deletion.
 * Provide results after operation.
 *
 */
function delSimRowsGUI() {
  var ui = SpreadsheetApp.getUi();
  var choice = ui.alert("Confirm action", 
                         "This will delete rows in the current sheet that contain sets of cells that already appear together in other rows.",
                         ui.ButtonSet.OK_CANCEL);
  if (choice === ui.Button.OK) {
    var numDeleted = delSimilarRows();
    ui.alert("Deleted "+numDeleted+" row"+(numDeleted===1?'.':'s.'));
  }
}

/**
 * Delete rows in the current sheet that contain sets of cells that already 
 * appear together in other rows. (Almost duplicates, but order-independent.)
 * From: https://stackoverflow.com/a/37304191/1677912
 *
 * @returns {Number}       The number of matching rows that were deleted.
 */
function delSimilarRows() {
  // Get all rows from sheet.
  var currentSheet = SpreadsheetApp.getActiveSheet();
  var data = currentSheet.getDataRange().getValues();
  var numDeleted = 0;
  
  // Sort cells within rows, and join into a string with (hopefully!) unique delimiter
  var sorted = data.map(function(row) {
    return row.sort().join(' |-| ');
  });
  
  // Identify duplicate rows in the sorted data, and delete the corresponding
  // spreadsheet rows. (Note: looping backwards, so deletion is clean.)
  for (var row=sorted.length-1; row>=0; row--) {
    if (sorted.slice(0,row).indexOf(sorted[row]) !== -1) {
      currentSheet.deleteRow(row+1);
      numDeleted++;
    }
  }
  return numDeleted;
}

完成所有实际工作的函数是delSimilarRows()。它使用一些 JavaScript 魔法来识别要删除的行,并直接从当前工作表中删除它们。

它处理所有类型的数据,通过临时将行转换为其字符串表示,单元格内容按字母顺序排序,并在它们之间(希望)唯一的分隔符。这样做,您的示例数据将如下所示(仅对计算机显示):

[ "cat |-| dog",
  "apple |-| orange",
  "blue |-| red",
  "cat |-| dog" ]

然后,我们可以在行数组的slices 上使用 JavaScript Array.indexOf() 方法循环检查是否存在重复项,不包括当前行。

因为我们正在处理从 0 开始的 JavaScript 数组以及从 1 开始的电子表格行,所以在索引其中一个或另一个时,我们需要小心添加或减去 1

/**
 * Delete rows in the current sheet that contain sets of cells that already 
 * appear together in other rows. (Almost duplicates, but order-independent.)
 * From: https://stackoverflow.com/a/37304191/1677912
 *
 * @returns {Number}       The number of matching rows that were deleted.
 */
function delSimilarRows() {
  // Get all rows from sheet.
  var currentSheet = SpreadsheetApp.getActiveSheet();
  var data = currentSheet.getDataRange().getValues();
  var numDeleted = 0;

  // Sort cells within rows, and join into a string with (hopefully!) unique delimiter
  var sorted = data.map(function(row) {
    return row.sort().join(' |-| ');
  });

  // Identify duplicate rows in the sorted data, and delete the corresponding
  // spreadsheet rows. (Note: looping backwards, so deletion is clean.)
  for (var row=sorted.length-1; row>=0; row--) {
    if (sorted.slice(0,row).indexOf(sorted[row]) !== -1) {
      currentSheet.deleteRow(row+1);
      numDeleted++;
    }
  }
  return numDeleted;
}

【讨论】:

  • 令人印象深刻。谢谢你。这正是我想做的。
【解决方案2】:

我没有使用 Google 表格的经验,但我将在 Excel 中执行以下操作,希望您能以某种方式复制它。

正如评论所暗示的,使用Remove Duplicates 可以满足您的要求,但首先您需要以一种能够拾取这些重复项的方式对列表进行规范化。

在 C 列中:=IF(A1<B1,A1,B1)

在 D 列中:=IF(A1<B1,B1,A1)

这实际上会将列 A 和 B 中的值按字母顺序排列在列 C 和 D 之间,然后您可以在这两个新列上执行 Remove Duplicates

【讨论】:

  • 简单又好。然后在谷歌表格中使用公式=UNIQUE(C:D)
【解决方案3】:

基于 Oliver Carr 提供的 sulution,这里是单一配方解决方案:

=unique(arrayformula({IF(A:A<B:B,A:A,B:B),IF(A:A<B:B,B:B,A:A)}))

【讨论】:

    【解决方案4】:

    对于多行甚至更多列的灵活解决方案,试试这个:

    假设您的数据在 A:G 列中,从第 1 行开始。

    上半年:=2^COUNTIF($A:$G,"&lt;"&amp;A1) 将此公式从 H 复制到 N,并根据需要向下复制尽可能多的行以覆盖所有数据单元格。

    在 O1 中:=SUM($H:$N) 并将其复制下来以覆盖所有行。

    对于具有相同单词的行,O 中的值将相同。您现在可以删除 O 列上的重复项。

    您所做的是为数据中的每个单词分配 2 的唯一幂,并且总和保证是唯一的(考虑一个二进制数,其位数与唯一单词的位数相同,每个位数设置为 1如果该单词出现在行中,否则为零)。

    如果您想要更精简的版本,也可以将其输入为数组公式(再次使用 A:G 中的数据):

    在 H1 中:=SUM(2^COUNTIF(A:G,"&lt;"&amp;A1:G1)) 按 Cntl+Shift+Enter 进入 或在 Google 表格中:=ArrayFormula(SUM(2^COUNTIF(A:C,"&lt;"&amp;A1:C1)))

    如果您仅限于使用 Google 表格,则可以使用 H 上的 UNIQUE 函数来获取唯一的 ID 列表,并对原始表执行查找以获取实际行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多