Как я могу удалить дубликаты, не удаляя мою формулу другие столбцы? - PullRequest
2 голосов
/ 31 марта 2020

Вот моя простая форма:

Col A:       Col B:    Col C:                       Col D:
010Mar0100   Link      =mid(A2,find(".",A2)-10,10)  =vlookup(C2,MAIN!B:B,1,false)
010Mar0110   Link      =mid(A3,find(".",A3)-10,10)  =vlookup(C3,MAIN!B:B,1,false)
020Mar0100   Link      =mid(A4,find(".",A4)-10,10)  =vlookup(C4,MAIN!B:B,1,false)
020Mar0100   Link      =mid(A5,find(".",A5)-10,10)  =vlookup(C5,MAIN!B:B,1,false)
030Mar0100   Link      =mid(A6,find(".",A6)-10,10)  =vlookup(C6,MAIN!B:B,1,false)

Col C, и D имеет формулу, которая возвращает значение, которое мне нужно. Полковники A и B получают refre sh ежедневно

Я хотел добавить скрипт для удаления дубликатов без удаления формулы в столбцах col C и D

Каждый раз, когда я использую этот скрипт, он делает который.

function removeDuplicates() {
  var ss = SpreadsheetApp.getActive();
  var sheet = ss.getSheetByName('Data');
 var rng = sheet.getRange("A2:B")
var data = rng.getValues();
var newData = new Array();
for(i in data){
var row = data[i];
var duplicate = false;
for(j in newData){
  if(row.join() == newData[j].join()){
    duplicate = true;
  }
}
if(!duplicate){
  newData.push(row);
}
}
rng.clearContents();
sheet.getRange(1, 1, newData.length, 
newData[0].length).setValues(newData);
}

Что мне нужно изменить, чтобы заставить его фокусироваться только на столбцах A и B?

Ответы [ 4 ]

3 голосов
/ 31 марта 2020

Использовать встроенный removeDuplicates :

const remD = () =>
  SpreadsheetApp.getActive()
    .getSheetByName('Data')
    .getRange('A2:B')
    .removeDuplicates();
1 голос
/ 31 марта 2020

Добавьте столбец после столбца D и добавьте эту функцию в этот столбец. Он будет в основном добавлять уникальный / дублированный текст в строку, которая является уникальной или двойной, на основе значений в столбцах A и B. Вы можете использовать даже ArrayFormula перед функцией If

= ArrayFormula (IF (COUNTIFS ($ A $ 1: $ A1, A1, $ B $ 1: $ B1, B1) = 1, "Unique", "Duplicate"))

После заполнения этого поля вы можете фильтровать только те строки, которые имеют " «уникально» на полковнике Е, и у вас будут все уникальные строки с неизменными формулами

Теперь, если честно, я взял эту информацию в Интернете. Я пытался исследовать его, чтобы использовать для справки, но не смог найти снова.

1 голос
/ 31 марта 2020

getValues() возвращает двумерный массив. Если вы хотите удалить дублирующиеся строки, вы должны удалить внутренние массивы (элементы внешнего массива, которые являются дубликатами).

Это можно сделать, используя , уменьшить и некоторые , например:

function removeDuplicates() {
  var ss = SpreadsheetApp.getActive();
  var sheet = ss.getSheetByName('Data');
  var rng = sheet.getRange("A2:B")
  var data = rng.getValues();
  var uniqueRows = data.reduce((unique, row) => {
    var duplicate = unique.some(uniqueRow => JSON.stringify(uniqueRow) === JSON.stringify(row));
    if (!duplicate) unique.push(row);
    return unique;
  }, []);
  rng.clearContent();
  sheet.getRange(2, 1, uniqueRows.length, uniqueRows[0].length).setValues(uniqueRows);
}

После получения массива уникальных строк (называемых uniqueRows), вам просто нужно:

  • Удалить все предыдущее содержимое в диапазон с clearContent () (не clearContents()).
  • Запишите uniqueRows на свой лист с помощью setValues.

Примечание:

Ссылка:

1 голос
/ 31 марта 2020

Решения

То, что вы хотите сделать, сводится к фильтрации неуникальных элементов из списка. Если я правильно понимаю, что вы хотите сохранить неповрежденными столбцы C и D, вам просто нужно сделать логику c более понятной, введя вспомогательную функцию (кстати, includes требует переключения на среду выполнения V8 , если это не новый проект) и setValues для того же rng (см. Улучшение ниже 3)

/**
 * Removes duplicates
 * @param {any[]} array 2D input
 * @returns {any[]} filtered input
 */
const filterDuplicates = (array) => {
  const stack = [];
  
  return array.filter(elem => {
    const joined = elem.join('');
    
    if( stack.includes(joined) ) {
      return false;
    }
    
    stack.push(joined);
  
    return true;
  });
};

const [ input, output, tbody, tbody_init ] = document.querySelectorAll('#input, #output, #grid_init, #grid');

const buildCellGrid = (parent, grid) => {
  parent.innerHTML = '';

  for(const row of grid) {
    const tr = document.createElement('tr');
    
    for(const cell of row) {
      const td = document.createElement('td');
      td.textContent = cell;
      tr.append(td);
    }
    
    parent.append(tr);
  }
};

input.addEventListener('change',event=> {
  const { value } = event.target;
  
  const parsedVal = JSON.parse(value);
  
  const filtered = filterDuplicates(parsedVal);
  
  output.textContent = JSON.stringify(filtered, null, '');
  
  buildCellGrid(tbody_init, filtered);
 
  buildCellGrid(tbody, parsedVal);
});
p, textarea {
  margin: 0 2vw; 
}

textarea {
  padding: 2vh 2vw;
  line-height: 2;
  resize: none;
  width: 125px;
  height: 125px;
}

table {
  margin: 2vh 2vw;
  border-collapse: collapse;
}

th, td {
  padding: 1vh;
  border: 1px solid darkgrey;
}
<p>
Enter valid 2D Array
</p>
<textarea id="input"></textarea>
<textarea id="output"></textarea>

<table>
  <caption>Initial</caption>
  <tbody id="grid_init"></tbody>
</table>

<table>
  <caption>Filtered</caption>
  <tbody id="grid"></tbody>
</table>

Улучшения

  1. Вы можете отказаться от вызова Array конструктора (new Array() ) к более распространенным и менее многословным буквальным обозначениям []. Единственная интересная особенность - это выделение пустого Array длины N с new Array(N) (я иногда использую его с fill(whatever_value)).
  2. Не используйте for...in для массивов - это утверждение имеет его собственное использование (с Object с). Пожалуйста, используйте for...of, который предназначен для работы.
  3. Вам не нужно getRange() new Range для обновленных значений, так как они по определению являются подсеткой исходных значений, и вы предварительно очищаете диапазон с clearContents() [Я полагаю Вы имели в виду clearContent()].

Примечания

  1. Если вы заинтересованы Вот полуинтерактивное сравнение подходов к созданию нового экземпляра Array:

const li = (parent) => (txt) => {
  const elem = document.createElement('li');
  elem.textContent = txt || 'undefined';
  parent.append(elem);
}

const forAll = (...args) => (callback) => {
  for(const arg of args) {
    callback(arg);
  }
};

const genConstrArr = (numElems) => {
  const temp = [];
 
  let i = 0;
  while(i < numElems) {
    temp.push(`${i++} elem`);
  }
  
  return new Array(...temp);
};

const genArr = (numElems) => {
  const arr = [];
  
  let i = 0;
  while(i < numElems) {
    arr.push(`${i++} elem`);
  }
  
  return arr;
};

const buildList = (container, array) => {
  const lists = container.querySelectorAll('ul');
  const [inList, ofList, keysList, ownList, symList] = lists;
  
  forAll(...lists)(list => list.innerHTML = '');
  
  for(const key in array) {
    li(inList)(key);
  }

  forAll(...array)( li(ofList) );

  const emptyKeys = Object.keys(array);
  forAll(...emptyKeys)( li(keysList) );

  const names = Object.getOwnPropertyNames(array);
  forAll(...names)( li(ownList) );

  const symbols = Object.getOwnPropertySymbols(array);
  forAll(...symbols)( li(symList) );

  forAll(...lists)(list => !list.hasChildNodes() && li(list)('[Empty]')); 
};

const boxes = document.querySelectorAll('#constructor, #constructor_filled, #literal');

const form = document.forms.array_control;
form.addEventListener('change', event => {
  const { value } = event.target;

  buildList(boxes[0], new Array(+value));  
  buildList(boxes[1], genConstrArr(+value));
  buildList(boxes[2], genArr(+value));
});
input {
  margin: 4vh 0;
}

ul {
  list-style: none;
  padding: 0;
}

table {
  border-collapse: collapse;
}

th, td {
  border: 1px solid black;
  padding: 2vh 2vw;
}

td {
  vertical-align: baseline;
}
<form id="array_control">
  <label for="elems">Number of elements:</label>
  <input id="elems" min="0" name="elems" type="number" />
</form>

<table>
  <thead>
    <tr>
      <th></th>
      <th>for...in</th>
      <th>for...of</th>
      <th>Object.keys()</th>
      <th>getOwnPropertyNames()</th>
      <th>getOwnPropertySymbols()</th>
    </tr>
  </thead>
  <tbody>
  
    <tr id="constructor">
      <th>Constructor (1 arg)</th>

      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
    </tr>    
  
    <tr id="constructor_filled">
      <th>Constructor (>1 arg)</th>

      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
    </tr>

    <tr id="literal">
      <th>Literal</th>

      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
      <td><ul></ul></td>
    </tr>
  </tbody>
</table>

Ссылки

  1. JS Лексическая грамматика на MDN
  2. Перечислимость и собственность свойств
  3. Set встроенных документов в MDN
  4. for...in документы и for...of документы на MDN
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...