给定 google 工作表中的任务和所有者列表,如何有效地提取个人计划?

How to efficiently extract Individual Plannings given a list of Tasks and Owners in google sheets?

基于以下 table 个任务:

PROJECT     TASK    START       END         IN CHARGE
P1          Task 1  16/03/2021  19/03/2021  AAA
P1          Task 2  16/03/2021  19/03/2021  BBB
P1          Task 3  31/03/2021  31/03/2021  AAA
P2          Task 4  06/04/2021  07/04/2021  
P2          Task 5  17/03/2021  07/04/2021  BBB
P2          Task 6  20/04/2021  15/04/2021  
P3          Task 7  06/04/2021  15/04/2021  CCC

我正在尝试制定以下计划:

IN CHARGE    16/03    17/03   18/03   19/03 
  AAA         P1      P1      P1      P1            
  BBB         P1      P1/P2   P1/P2   P1/P2  
  CCC                           

目前,我正在使用以下公式来执行此操作,但我需要将它放在每个单元格中才能正常工作,当负责人的不同值数量很大时,速度会变得非常慢。

=ARRAYFORMULA(IFERROR(
  SI($A3<>"";
    JOIN("/"; UNIQUE(

      FILTER(INPUT!$A:$A;
             INPUT!$C:$C<=B; 
             INPUT!$D:$D>=B;
             INPUT!$E:$E=$A3)
    ))
  ;"")
;""))

有没有有效的方法来计算这个?

我有一个关于此的通用示例 link :

GSheet GANTT

我不确定您是否可以只使用公式高效地完成它,但是您可以使用 Google App Script 在 javascript 中最佳地实现您的功能。

您可以先收集一组所有者和所有日期的列表,然后通过遍历任务构建结果 table。

这是一个示例实现:

https://docs.google.com/spreadsheets/d/1zk01y8wwLvjJPwc3ov8f2NDUMIEcxPWMNhciFXvCaVw/edit?usp=sharing

和 javascript 代码:

class Task{
  /**
   * @param {[string, string, Date, Date][]} tasks
   */
  constructor(cells) {
    this.project = cells[0];
    this.owner = cells[1];
    this.start = cells[2];
    this.end = cells[3];
  }
}
/**
 * @param {[string, string, Date, Date][]} tasks
 */
function makeTimeSheet(task_cells) {
  task_cells = remove_empty(task_cells);
  const tasks = task_cells.map(cells => new Task(cells));
  console.log(`Running makeTimeSheet on the following ${tasks.length} tasks`);
  const start = new Date(Math.min(...tasks.map(t => t.start)));
  const end = new Date(Math.max(...tasks.map(t => t.end)));
  const header = ["", ...days_in_task({start, end})];
  const results = owners_dates(tasks);
  const table = final_table(results, start);
  table.unshift(header);
  console.log(`Returning a table with ${table.length} lines and ${table[0].length} columns`);
  return table;
}

/**
 * In an array of arrays, remove all the empty inner arrays.
 * This is required to work on infinite google sheet ranges
 */
function remove_empty(arr){
  return arr.filter(arr => arr.some(x => x));
}

/**
 * @param {{start:Date, end:Date}} task
 */
function* days_in_task(task) {
   const day = 24*60*60*1000;
   const duration = task.end - task.start;
   if (duration < 0 || duration > 365*day) throw new Error(`Invalid task: ${JSON.stringify(task)}`);
   let d = new Date(task.start);
   while(d <= task.end) {
     yield d;
     d = new Date(d.getTime()+day);
   }
}


// Given a map and a key,
// returns the value associates with the given key in the map if it exists
// otherwise insert a value using the given default_val function and returns it
function get_or_default(map, key, default_val){
      let value = map.get(key);
      if (value === undefined) {
         value = default_val();
         map.set(key, value);
      }
      return value;
}

// Returns a mapping from owner to a mapping from dates to projects
function owners_dates(tasks){
   const result = new Map();
   for(const task of tasks) {
      const owner = get_or_default(result, task.owner, () => new Map);
      for(const date of days_in_task(task)) {
         const projects = get_or_default(owner, date.getTime(), () => new Set);
         projects.add(task.project);
      }
   }
   return result;
}

function final_table(results, start) {
   const day = 24*60*60*1000;
   return Array.from(results).map(([owner, dates])=> {
     const line = [owner];
    for([date, projects] of dates) {
      line[1 + (date - start)/day] = [...projects].join(", ")
    }
    return line;
   });
}