Algorithm 如何优化非递归展平算法

Algorithm 如何优化非递归展平算法,algorithm,optimization,google-apps-script,large-data,flatten,Algorithm,Optimization,Google Apps Script,Large Data,Flatten,我正在与谷歌应用程序脚本环境合作,为谷歌的DataStudio创建一个社区连接器。其思想是调用外部API并解析数据,使DataStudio能够从中正确创建图表或表格 我目前正在尝试降低加载时间,我发现最大的时间消耗是更改API响应,例如 { campaigns: [{ name_campaign: Example_Name, ads: [ {cost: 15.98} ], budget: 237.59 }, { name_campa

我正在与谷歌应用程序脚本环境合作,为谷歌的DataStudio创建一个社区连接器。其思想是调用外部API并解析数据,使DataStudio能够从中正确创建图表或表格

我目前正在尝试降低加载时间,我发现最大的时间消耗是更改API响应,例如

{
  campaigns: [{
    name_campaign: Example_Name,
    ads: [
      {cost: 15.98}
    ],
    budget: 237.59
  },
  {
    name_campaign: Another_Name,
    ads: [
      {cost: 98.25},
      {cost: 13.03},
      {cost: 23.44}
    ],
    budget: 15.50
  },
  ...
}
按照DataStudio的预期,这是一个平面数据集

[
  [237.59, Example_Name, 15.98],
  [15.50, Another_Name, 98.25],
  [15.50, Another_Name, 13.03],
  [15.50, Another_Name, 23.44]
]
诀窍在于,由于对API的调用是动态创建的,因此无法知道将有多少字段或多少不同的对象。可能只有一个对象有两个字段或类似于上面的内容。幸运的是,它被限制为只有父母/子女关系,而不是兄弟姐妹关系

迄今为止的算法是一个非递归循环,它查找最深的对象并保留最后一个对象/循环中的所有字段。如果有更深的物体,它会重复这个过程。如果没有,则它将获取最低对象的字段和所有以前存储的字段,将它们合并在一起,并将它们作为要返回的行追加。代码也用逻辑进行了注释,希望对您有所帮助

function stackIt(data) {
  var totalData = [];

  //create stack with highest object
  var stack = [{
    v: data,
    parent_fields: []
  }];

  var stackLen = stack.length;
  var pushing = 0, totalFields = 0;
  var data_fields, array_field, cl, v, current_fields, temp, arr_len, row, parentFields;

  while (stackLen > 0) {
    //store current node 
    cl = stack.pop();
    if (cl === undefined)
      break;

    v = cl.v;
    parentFields = cl.parent_fields.slice(0);

    //fill new array with all parents
    data_fields = parentFields.slice(0);
    array_field = null;
    current_fields = [];

    //Does another object exist?
    //Keep track of all current fields on the chance that no objects exists below
    for (var field in v) {
      //Hold the current field
      temp = v[field];
      current_fields.push(temp);

      //found an object. So we know we need to move deeper with the current object
      if (typeof(temp) === 'object' && temp != null && array_field == null)
        array_field = field;
      //store current parent fields
      if (typeof(temp) !== "object")
        data_fields.push(temp)
    }

    //Push new node to stack to delve deeper
    //each one with with parent data points to tack on later for deepest level objects
    if (array_field != null) {
      for (var i = 0, arr_len = v[array_field].length; i < arr_len; i++) {
        //Skip broken fields
        if ('errors' in v[array_field][i])
          continue;

        stack.push({
          v: v[array_field][i],
          parent_fields: data_fields
        });
      }      
    }
    //No object exists below
    else {
      row = [];
      //re set data fields if no object was found
      //data_fields is changed in above function on the chance that there is an object below
      data_fields = parentFields.slice(0);

      //get total number of fields that should exist
      //this is to prevent pushing rows with only a subset of fields
      //only do once at deepest object to get total number of fields expected
      if (pushing == 0) {
        pushing = 1;
        totalFields = data_fields.length + current_fields.length;
      }

      //push parents fields (ex. camp.cost)
      row = data_fields.splice(0);

      //push all current fields held (ex. keyword.cost)
      row = row.concat(current_fields);
      //comes out to camp.cost, keyword.cost

      //Push all rows at lowest level; exit if done.
      if (row.length != totalFields) {
        console.log("End Stack"); 
        return totalData;
      }
      else
        totalData.push(row);
    }
  }

  console.log("End Stack with empty stack"); 
  return totalData;
}
函数堆栈(数据){
var totalData=[];
//创建具有最高对象的堆栈
变量堆栈=[{
五:数据,,
父字段:[]
}];
var stackLen=stack.length;
var=0,totalFields=0;
var数据字段、数组字段、cl、v、当前字段、temp、arr长度、行、父字段;
而(stackLen>0){
//存储当前节点
cl=stack.pop();
如果(cl==未定义)
打破
v=cl.v;
parentFields=cl.parent\u fields.slice(0);
//用所有父数组填充新数组
数据\字段=父字段。切片(0);
数组_字段=null;
当前_字段=[];
//是否存在另一个对象?
//跟踪所有当前字段,以确保下面不存在任何对象
for(v中的var字段){
//保留当前字段
温度=v[场];
当前_字段推送(温度);
//找到了一个对象。所以我们知道我们需要用当前对象向更深的方向移动
if(typeof(temp)=='object'&&temp!=null&&array\u字段==null)
数组\字段=字段;
//存储当前父字段
if(类型(温度)!=“对象”)
数据字段推送(临时)
}
//将新节点推到堆栈以深入挖掘
//每一个都有父数据点,以便稍后为最深级别的对象附加
if(数组_字段!=null){
对于(变量i=0,arr\u len=v[array\u field]。长度;i

我曾尝试使用开源库
cFlatten
,但这使得展平速度慢得多,我发现的大多数工具只需要1-2个对象深度,并且需要特定的格式。该算法过去是递归的,但由于返回的数据量太大,因此速度要慢得多。任何关于如何使功能更快/更高效的想法都将不胜感激

如果一个对象有一个以上的数组字段或一个以上的对象字段或一个数组和一个对象字段使用
array.prototype.push.apply(row,current_字段),我看不出这种方法有效
可以尝试对输入活动数组进行排序,这样您就可以首先获得最深的对象,并可以立即构建对象数组关系,之后您只需尝试推送该值,并根据需要将默认值设置为
未定义的
/
null
。或者,在解析连接和映射总排列的过程中,通过询问用户希望从每个对象级别获得哪些头来隐藏延迟。