Функция сопоставления со сценарием приложений для поиска ближайших, но меньших дат

#javascript #google-apps-script #google-sheets

Вопрос:

У меня есть множество дат. У меня есть конкретная дата «Дата поиска». Я хочу найти дату в массиве, которая ближе всего к Дате поиска, но меньше, чем дата поиска, и вернуть индекс этой даты в массиве.

Пример: Предположим , что массив дат [8/1/21, 8/5/22, 8/5/23] проиндексирован 1,2,3 для примера. Предположим, что моя дата поиска такова 9/17/22 . Функция должна найти дату 8/5/22 и вернуть индекс 2 .

В Google Таблицах это просто функция сопоставления: введите описание изображения здесь

Как это сделать (и наиболее эффективно) в сценарии приложений? IndexOf() Функция, похоже, возвращает только точное совпадение, которое в данном случае не работает.

Спасибо!

Ответ №1:

Объяснение:

Идея состояла бы в том, чтобы сравнить каждую дату в массиве с датой поиска и выбрать абсолютную минимальную разницу, которая будет ближайшей датой к дате поиска:

 const checkDif = checkDates.map(d=>searchDate - d).filter(v=>v>0);
const minIndex = checkDif.indexOf(Math.min(...checkDif)) 1;
 
  • карта используется для вычисления разницы между датами для каждой даты во входном массиве.
  • фильтр используется для выбора только положительных различий (а именно дат, которые меньше даты поиска).
  • Математич.мин используется для вычисления минимального значения массива положительных разностей, следовательно, ближайшая дата, которая меньше даты поиска.
  • indexOf используется для вычисления индекса этого минимального значения.

Мы делаем 1 это, потому что индексы массива JavaScript начинаются с 0 , но, похоже, вы хотите, чтобы они начинались с 1 .

Решение:

Дополнительные пояснения см. в комментариях, а также в случае, если вы хотите изменить диапазоны или название листа.

 function closestDate() {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName("Sheet1"); // name of the sheet
  const searchDate = sh.getRange("B4").getValue(); // search date
  const checkDates = sh.getRange("B1:D1").getValues().flat(); // input range
  const checkDif = checkDates.map(d=>searchDate - d).filter(v=>v>0);
  const minIndex = checkDif.indexOf(Math.min(...checkDif)) 1;
  console.log(minIndex); // 2
  sh.getRange("B5").setValue(minIndex); // return the result to B5
}
 

Пример, который работает с фрагментом кода:

введите описание изображения здесь

Комментарии:

1. Это так невероятно полезно. Спасибо. Ваш код и объяснение удивительны. У меня есть один последующий вопрос. Моя цель-получить индекс исходного массива дат. Ваш код, приведенный выше, работает, потому что я перечислил даты в порядке возрастания, от самой старой до самой новой даты. Однако, если даты в массиве были расположены в случайном порядке, указанный вами код даст индекс отфильтрованного массива положительных значений. Поэтому, если даты не в порядке, это будет неправильный индекс. Видите ли вы способ изменить то, что вы написали, чтобы получить минимальное положительное значение вашего checkDif массива?

2. @КимХопкинс, порядок дат не имеет значения. Код сравнивает различия, а затем находит минимальное положительное значение. Позиция на этом шаге не имеет значения, поскольку индекс рассчитывается методом indexof. Так что порядок не имеет значения. Если вы считаете иначе, отредактируйте свой вопрос и включите пример, который, по вашему мнению, не работает. Также подумайте о том, чтобы принять и проголосовать за ответ, когда он решит проблему

3. ОК. Я подумал, что, поскольку код отфильтрован на наличие положительных различий, этот фильтр создаст новый массив, и поэтому индекс будет соответствовать новому массиву по сравнению с исходным массивом. В случае, например, если даты были в обратном хронологическом порядке, я думал, что из-за этого он вернет неправильный индекс. Еще раз спасибо вам. Я не могу озвучивать, потому что я новичок, но я очень признателен вам за ваш отчет.