SUMIF с несколькими условиями со скриптом приложений Google

Я пытаюсь написать скрипт приложений Google, похожий на SUMIF в листах Google. Моя цель - суммировать все значения в часах столбца для всех строк, которые содержат определенный идентификатор (id) в течение определенного периода (период столбца), которые помечены как продуктивные (продуктивный = 1) и значение единицы столбца для конкретной строки отличается от строки, указанной ниже. По какой-то причине это не работает. Я новичок в javascript и не могу понять, почему он не работает. Я попытался определить функцию суммы, а затем вызвать ее для каждого значения в столбце идентификатора (около 7000 строк).

//Productive hours  
//=if ($A2<> "", SUMIFS(hours,hrmid,$AC2, productive,1,period,$A2)-SUMIFS(hours,hrmid,$AC2, productive,1,period,$A2, units,"Revision Stand-by"), "")
  function sumPrdHrs (item) {
    var hoursToSum = 0;
    var summedHrs = [];
    var hours = ytdSheet.getRange(2,18, ytdSheet.getLastRow()).getValues();
    var productive = ytdSheet.getRange(2,33, ytdSheet.getLastRow()).getValues();
    var units = ytdSheet.getRange(2, 9, ytdSheet.getLastRow()).getValues();
    var id= ytdSheet.getRange(2,29, ytdSheet.getLastRow()).getValues();
    var period = ytdSheet.getRange(2,1, ytdSheet.getLastRow()).getValues();
    //var date = ytdSheet.getRange(2,1, ytdSheet.getLastRow()).getValues();
    
    for (var i=0; i < hours.length; i++) {
      if ((id[i][0] == item) && (productive[i][0] == 1) && (period[i][0] == period[i+1][0]) && (units[i][0] != "Revision Stand-by")) {
      hoursToSum += hours[i][0];
      summedHrs.push(hoursToSum);
      }      
    }
    return sumPrdHrs;
    console.info(summedHrs);
}
  
function productiveHrs () {

  var id= ytdSheet.getRange(2,29, ytdSheet.getLastRow()).getValues();
  var sumHours = [];
  
  id.forEach(function(item,i) {
                
     var summedHours = sumPrdHrs (item);    
    
    //sumHours.push(summedHours);
    
    //Logger.log(summedHours);
    
   // ytdSheet.getRange(2,31,hrmId.length,1).setValues(summedHours);
                
                });
  
 

}

Можете ли вы дать скриншот того, над чем вы пытаетесь работать?

NightEye 10.12.2020 17:05

Обновил мой ответ ниже. Также были внесены некоторые изменения в ваши условия, которые, как мне кажется, лучше подходят для того, что вы делаете. Пока что он делает то, чего хотят ваши функции. Если у вас есть дополнительные условия, которые вы хотите добавить, вы сможете легко их добавить. не стесняйтесь комментировать ниже, если вам нужна помощь.

NightEye 10.12.2020 18:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
543
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

function sumPrdHrs (item) {
    var hoursToSum = 0; 

    // Removed summedHrs array. Based on your code structure, you want to return the sum of productive hours. 
    // I don't see any use of creating an array when you can already sum it up directly.

    var hours = ytdSheet.getRange(2,18, ytdSheet.getLastRow()).getValues();
    var productive = ytdSheet.getRange(2,33, ytdSheet.getLastRow()).getValues();
    var units = ytdSheet.getRange(2, 9, ytdSheet.getLastRow()).getValues();
    var id= ytdSheet.getRange(2,29, ytdSheet.getLastRow()).getValues();
    var period = ytdSheet.getRange(2,1, ytdSheet.getLastRow()).getValues();
    
    for (var i=0; i < hours.length; i++) {
      // In the conditions below, I don't get why you want to compare current period to the period below. 
      // It always makes the last item with the same period invalid since there is no last date. 
      // But will include it since it might be important to you
      // You also have another condition mentioned but wasn't added initially so I skipped it for now. But feel free to add it on your code.
      if ((id[i][0] == item) && (productive[i][0] == 1) && (period[i][0] == period[i+1][0]) && (units[i][0] != "Revision Stand-by")) {
        hoursToSum += hours[i][0]; 
        // Total hours is calculated per item, that's all you need to return below.
      }      
    }
    return hoursToSum;
}

// Based on what you want, this will sum all hours per item that follows the conditions above.
function productiveHrs () {
  // This will transform the 2d array into 1d array 
  var id = ytdSheet.getRange(2,29, ytdSheet.getLastRow()).getValues().flat();
  // We want to loop only the unique items, removing duplicates
  id = id.filter((item, i, ar) => ar.indexOf(item) === i);
  
  var sumHours = [];

  id.forEach(function(item,i) {
    // Skip blank/invalid items
    if (item) {
      var summedHours = sumPrdHrs(item);    
      sumHours.push(summedHours);      
    }
  });

  Logger.log(sumHours);
}

Это мой образец листа

это результат

Видите, что общее количество предметов b, которых должно быть 14, равно 10, верно? Это из-за условия периода, которое проверяет период ниже. Это то, что я обсуждал выше.

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

Это должно быть лучшим способом проверки периода.

// Added time for per item summation of hours
function sumPrdHrs (item, time) {
    var hoursToSum = 0;
    var hours = ytdSheet.getRange(2,18, ytdSheet.getLastRow()).getValues();
    var productive = ytdSheet.getRange(2,33, ytdSheet.getLastRow()).getValues();
    var units = ytdSheet.getRange(2, 9, ytdSheet.getLastRow()).getValues();
    var id = ytdSheet.getRange(2,29, ytdSheet.getLastRow()).getValues();
    var period = ytdSheet.getRange(2,1, ytdSheet.getLastRow()).getValues();
    
    for (var i=0; i < hours.length; i++) {
      // Compare period[i][0] to unique period fetched from productiveHrs() instead.
      if ((id[i][0] == item) && (productive[i][0] == 1) && (period[i][0] == time) && (units[i][0] != "Revision Stand-by")) {
        hoursToSum += hours[i][0];
      }      
    }
    return hoursToSum;
}

function productiveHrs () {
  // Get unique ids and periods
  var id = ytdSheet.getRange(2,29, ytdSheet.getLastRow()).getValues().flat();
  var period = ytdSheet.getRange(2,1, ytdSheet.getLastRow()).getValues().flat();
  id = id.filter((item, i, ar) => ar.indexOf(item) === i);
  period = period.filter((item, i, ar) => ar.indexOf(item) === i);
  
  var sumHours = [];

  // Traverse all combination of id and period
  id.forEach(function(item,i) {
    if (item) {
      period.forEach(function(time,j) {
        if (time) {
          // Pass period to sum hours under item per period
          var summedHours = sumPrdHrs(item, time);    
          // Only push data when where is summedHours
          if (summedHours) { 
            sumHours.push([item, time, summedHours]);  
          }    
        }  
      });
    }
  });

  Logger.log(sumHours);
}

Это пример данных:

Это результат:

Как видите, более красивый и читаемый вывод и условия, которые имели бы смысл.

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

Спасибо @Marios, я все еще жду комментариев/проверки ОП, поскольку он упомянул некоторые условия, которые я не включил в свой код. Хотя то, чего я думаю, он пытается добиться, уже включено сюда. и если он хочет добавить какие-то условия, он может легко добавить их.

NightEye 10.12.2020 19:26

Большое спасибо @Nazi A! Ваше решение отлично решило мою проблему! Я вижу, что не так с моим кодом.

JohnyDony 11.12.2020 11:57

Другие вопросы по теме