【问题标题】:how to extract multi layered array from json如何从json中提取多层数组
【发布时间】:2018-11-14 06:32:17
【问题描述】:

我有一个类似于以下架构的 JSON 响应...

{
    "resultCode": 200,
    "message": "Success",
    "generated": "2018-11-14T18:42:02",
    "expires": "2018-11-14T18:50:00",
    "data": {
        "generationByFuel": [
            {
                "date": "2018-11-14T00:00:00",
                "period": 37,
                "generation": [
                    {
                        "fuel": "Hydro",
                        "generation": 1011.298,
                        "capacity": 2000
                    },
                    {
                        "fuel": "Wind",
                        "generation": 2544.788,
                        "capacity": 3500
                    }
                ]
            },
            {
                "date": "2018-11-14T00:00:00",
                "period": 36,
                "generation": [
                    {
                        "fuel": "Hydro",
                        "generation": 1100,
                        "capacity": 2000
                    },
                    {
                        "fuel": "Wind",
                        "generation": 2500,
                        "capacity": 3500
                    }
                ]
            }
        ]
    }
}

据此,我需要提取多个数组,这些数组将插入到 googlesheet(“shtGen”)中,填充以下列:

|日期 |期间 |燃料 |一代 |容量 |运行时 |

我猜我需要做的是写一些输出 (generationByFuel[i](generation[r])) 的东西,但我正在努力弄清楚如何做到这一点。

我尝试了多种选择,但以下是我认为自己走在正确轨道上的最后一次尝试。也就是说,该函数运行时不会返回错误,但不会将任何信息插入到谷歌表中。当我使用调试器运行函数时,也会发生同样的事情。

// define output to paste into sheet
for (var i in genData) {
  var iInput = [];
  iInput.push(genData[i].date);
  iInput.push(genData[i].period);
  for (var r in fuelData) {
    var rInput = [];
    rInput.push(fuelData[r].fuel);
    rInput.push(fuelData[r].capacity);
    rInput.push(fuelData[r].generation);
    rInput.push(now = new Date());
    shtGen.appendRow(iInput + rInput);
  }
}

这里的任何帮助或建议将不胜感激。提前致谢!

【问题讨论】:

  • fuelData 应该在内部循环之前分配 fuelData = genData[i].generation
  • @Slai 抱歉,我确实声明了iInputrInput,但收到了危险信号,说我发布的代码多于文本,因此被删除。这些是我的声明...var genData = json['data']['generationByFuel'];var fuelData = json['data']['generationByFuel']['generation'];

标签: arrays json google-apps-script


【解决方案1】:

这个修改怎么样?我认为您的情况有几种解决方案。因此,请将此视为其中之一。

修改点:

  • fuelData 需要在第一个 for 循环中声明。
    • @Slai 提到了这一点。
  • iInput + rInput 成为字符串类型。这样,appendRow() 就会发生错误。
    • iInput.concat(rInput) 用于此目的。
  • 为了安排到| Date | Period | Fuel | Generation | Capacity | Runtime |,要求推送值的顺序是
    1. rInput.push(fuelData[r].fuel)
    2. rInput.push(fuelData[r].generation)
    3. rInput.push(fuelData[r].capacity)

在这个修改后的脚本中,obj 是您问题中的 json 对象。然后shtGen 假设工作表对象。

修改脚本:

var obj = {### your json object ###};
var genData = obj.data.generationByFuel;
for (var i in genData) {
  var iInput = [];
  iInput.push(genData[i].date);
  iInput.push(genData[i].period);
  var fuelData = genData[i].generation; // Added
  for (var r in fuelData) {
    var rInput = [];
    rInput.push(fuelData[r].fuel); // Modified
    rInput.push(fuelData[r].generation); // Modified
    rInput.push(fuelData[r].capacity); // Modified
    rInput.push(new Date());
    shtGen.appendRow(iInput.concat(rInput)); // Modified
  }
}

我认为当对象很大时,appendRow() 成为过程成本增加的原因。所以我建议使用setValues() 将值放入电子表格,如下所示。

var obj = {### your json object ###};
var res = [];
var genData = obj.data.generationByFuel;
for (var i in genData) {
  var iInput = [];
  iInput.push(genData[i].date);
  iInput.push(genData[i].period);
  var fuelData = genData[i].generation;
  for (var r in fuelData) {
    var rInput = [];
    rInput.push(fuelData[r].fuel);
    rInput.push(fuelData[r].generation);
    rInput.push(fuelData[r].capacity);
    rInput.push(new Date());
    res.push(iInput.concat(rInput)); // Modified
  }
}
shtGen.getRange(shtGen.getLastRow() + 1, 1, res.length, res[0].length).setValues(res); // Added

其他模式:

作为其他修改之一,您还可以使用以下脚本。此脚本的成本低于上述脚本。

var obj = {### your json object ###};
var res = obj.data.generationByFuel.reduce(function(ar, e) {
  return ar.concat(e.generation.map(function(f) {
    return [e.date, e.period, f.fuel, f.generation, f.capacity, new Date()];
  }));
}, []);
shtGen.getRange(shtGen.getLastRow() + 1, 1, res.length, res[0].length).setValues(res);

参考资料:

如果这不是你想要的,请告诉我。我想修改它。

【讨论】:

  • 感谢@Tanaike。我最初选择了您的“修改后的脚本”方法,效果很好。然后我今天早上有一些空闲时间仔细看看你在“其他模式”中做了什么。效果一样好,但使用的代码行更少……太棒了!谢谢
  • @mitch-NZ 感谢您的回复。我很高兴你的问题得到了解决。也谢谢你。
【解决方案2】:

这是一种利用 JSON.parse() 的替代方法。

Reviver 函数是JSON.parse() 的可选参数。这些函数最酷的地方在于,它们使用深度优先搜索的 JSON 对象树中的每个节点的键/值对来调用。

运行以下 sn-p 以了解其工作原理:

var jsonString = JSON.stringify({
        "resultCode": 200,
        "message": "Success",
        "generated": "2018-11-14T18:42:02",
        "expires": "2018-11-14T18:50:00",
        "data": {
            "generationByFuel": [
                {
                    "date": "2018-11-14T00:00:00",
                    "period": 37,
                    "generation": [
                        {
                            "fuel": "Hydro",
                            "generation": 1011.298,
                            "capacity": 2000
                        },
                        {
                            "fuel": "Wind",
                            "generation": 2544.788,
                            "capacity": 3500
                        }
                    ]
                },
                {
                    "date": "2018-11-14T00:00:00",
                    "period": 36,
                    "generation": [
                        {
                            "fuel": "Hydro",
                            "generation": 1100,
                            "capacity": 2000
                        },
                        {
                            "fuel": "Wind",
                            "generation": 2500,
                            "capacity": 3500
                        }
                    ]
                }
            ]
        }
    });

JSON.parse(jsonString, function(key, value) {
    console.log("Key:%s, Value:%o", key, value);
    return value;
});

上述脚本生成的控制台日志“遍历”对象树深度优先;它在打印父节点的值之前向下钻取以打印出叶节点的值。例如:"fuel":"Hydro" 在包含它的 "generation":[{...}, {...},..] 数组之前打印。

您可以利用它为您的电子表格生成必要的数据,如下所示:

var jsonString = JSON.stringify({
        "resultCode": 200,
        "message": "Success",
        "generated": "2018-11-14T18:42:02",
        "expires": "2018-11-14T18:50:00",
        "data": {
            "generationByFuel": [
                {
                    "date": "2018-11-14T00:00:00",
                    "period": 37,
                    "generation": [
                        {
                            "fuel": "Hydro",
                            "generation": 1011.298,
                            "capacity": 2000
                        },
                        {
                            "fuel": "Wind",
                            "generation": 2544.788,
                            "capacity": 3500
                        }
                    ]
                },
                {
                    "date": "2018-11-14T00:00:00",
                    "period": 36,
                    "generation": [
                        {
                            "fuel": "Hydro",
                            "generation": 1100,
                            "capacity": 2000
                        },
                        {
                            "fuel": "Wind",
                            "generation": 2500,
                            "capacity": 3500
                        }
                    ]
                }
            ]
        }
    });

var values = [];
var state = {};

JSON.parse(jsonString, function(key, value) {
    
    switch(key) {
        case "generation":
            if (Array.isArray(value)) break;
        case "date":
        case "period":
        case "fuel":
        case "capacity":
            state[key] = value;
            break;
    }
    
    if (key === "capacity") {
        values.push([
            state.date,
            state.period,
            state.fuel,
            state.generation,
            state.capacity,
            new Date()
        ]);
    }
    
    return value;
});

console.log(values);

上面的 sn-p 在 reviver 遍历 JSON 的对象树并在此过程中填充 2D 值数组时过滤掉所需的数据。现在您需要做的就是使用 values 数组在工作表上调用 setValues()

【讨论】:

  • @TheMaster 为我工作。
  • 感谢您的回答。虽然我可以看到您的建议在这种情况下有效,但我不熟悉 switchcasebreak 语句。直到我可以研究这些并理解为什么它会起作用,我已经接受了 Tanaike 对我的问题的回答。
  • @mitch-NZ 这是一个很好的起点:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
【解决方案3】:

我认为您错过了 for var 'r' 循环中的“genData[i]”。试试这个。

for (var i in genData) {
  var iInput = [];
  iInput.push(genData[i].date);
  iInput.push(genData[i].period);
  for (var r in fuelData) {
    var rInput = [];
    rInput.push(genData[i].fuelData[r].fuel);
    rInput.push(genData[i].fuelData[r].capacity);
    rInput.push(genData[i].fuelData[r].generation);
    rInput.push(now = new Date());
    shtGen.appendRow(iInput + rInput);
  }
}

这也可以是您在模型类中存储响应的方式。

【讨论】:

  • 感谢您的回答。在提交我的问题之前,我已经尝试过这个以及这个的许多变体。但是我能得到的最好结果是脚本完成而不返回错误,但它只会输出dateperiod
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多