【问题标题】:(Recursion) How to get all key/value pairs from an Object with nested objects and arrays(递归)如何从具有嵌套对象和数组的对象中获取所有键/值对
【发布时间】:2020-12-14 14:23:58
【问题描述】:

我有一个看起来像这样的对象:

        {
            "id": 45745049
            "seller": {
                "first_name": "Sam",
                "last_name": "Smith",
                "email": "samsmith@smith.com",
                "phone": {
                    "number": "1111-1111",
                    "verified": false
                },
            },
            "order_items": [
                {
                    "item": {
                        "id": "29239765",
                        "title": "item1",
                        "colors": [
                             "red",
                             "green",
                             "blue"
                        ]
                    },
                    "quantity": 1,
                    "unit_price": 230,
                },
                {
                    "item": {
                        "id": "238457363",
                        "title": "item2",
                        "colors": [
                             "red"
                        ]
                    },
                    "quantity": 2,
                    "unit_price": 110,
                }
            ],
            "date_created": "2020-08-03T12:17:25.000-04:00",
            "date_last_updated": "2020-08-03T16:51:35.61Z"
        }

我想要一个数组,其中包含对象中每个键对的值。

例如:

[
  ["id", 45745049], 
  ["first_name", "Sam"], 
  ....., 
  ["phone.number", "1111-1111"], 
  ["phone.verified", false], 
  ....etc
]

在那之前一切都好。问题是当一个属性是一个对象数组时。我想要的输出如下:

[
   ..., 
   ["order_items1.item.id", 29239765], 
   ["order_items1.item.colors1", "red"], 
   ["order_items1.item.colors2", "green"], 
   ..., 
   ["order_items2.item.id", 238457363], 
   ["order_items2.item.colors1", "red"], 
   ...etc
]

所以它需要检查属性是否为数组,如果是则添加位置编号。

我知道我需要一个递归函数,但我不知道该怎么做。 这是我到现在为止得到的。

getObjectKeys = (obj) => {
    let FieldName = "";
    let FieldValue = "";
    for(var prop in obj) {
        FieldName += prop;
        if(!(prop instanceof Array) && (typeof prop !== "object") && obj[prop]) {
            FieldValue = obj[prop];
        } else if(prop instanceof Array && prop.length !== 0){
            prop.forEach((innerItem, i) => {
                FieldName += `${i+1}.`;
                // check if the inner item is an array or whatever an do it all again
                // Dont know what to do here.                   
            });
        } else {
            getObjectKeys(obj[prop]);
        }        
    }
    return [FieldName, FieldValue];
    
}

注意:我不想要空或空键。

如果有人可以帮助我,我将不胜感激。还是谢谢!

【问题讨论】:

  • 你确定要["order_items1.item.id", 29239765]吗?由于 key 内的点,这不是一个正确的数组。如果你例如从这个数组中创建一个console.log,这个键/值对不存在。只能通过arr["order_items1.item.id"]地址获取值。
  • @Sascha 是的,我知道。但我不想稍后访问该密钥。只需要作为字符串的键

标签: javascript arrays function object recursion


【解决方案1】:

这与您正在寻找的东西非常相似。这是一种技术I use often

const getPaths = (obj) =>
  Object (obj) === obj
    ? Object .entries (obj) .flatMap (([k, v]) => getPaths (v) .map (p => [k, ... p]))
    : [[]]

const path = (ps) => (obj) => 
  ps .reduce ((o, p) => (o || {}) [p], obj)

const flatten = (obj) => 
  Object .fromEntries (getPaths (obj) .map (p => [p.join('.'), path (p) (obj)]))

const input = {id: 45745049, seller: {first_name: "Sam", last_name: "Smith", email: "samsmith@smith.com", phone: {number: "1111-1111", verified: false}}, order_items: [{item: {id: "29239765", title: "item1", colors: ["red", "green", "blue"]}, quantity: 1, unit_price: 230}, {item: {id: "238457363", title: "item2", colors: ["red"]}, quantity: 2, unit_price: 110}], date_created: "2020-08-03T12: 17: 25.000-04: 00", date_last_updated: "2020-08-03T16: 51: 35.61Z"}

console .log (flatten (input))
.as-console-wrapper {min-height: 100% !important; top: 0}

不同之处在于数组索引之前有一个分隔符,并且我使用从零开始的数组,而不是从一开始的数组。

我建议这是一种更好的输出格式。如果不出意外,它可能会让您重新水化原始格式。但是如果你想改变它,你可能应该简单地reduce 将数字元素与其前辈组合的路径,例如:

const flatten = (obj) => 
  Object .fromEntries (getPaths (obj) .map (p => [
    p .reduce (
      (a, k) => /^\d+$/ .test(k) ? [...a .slice (0, -1), a [a .length - 1] + (1 + (+k))] : [...a, k], 
      []
    ) .join ('.'), 
    path2 (p) (obj)
  ]))

但如果外部对象可能是数组,则需要进行更改。

同样,尽管没有充分的理由使用您要求的格式,我强烈推荐我的替代方案。

【讨论】:

  • 非常感谢!!我不完全理解代码,也许我需要做一些调整,但这就是我想要的(有点)。我稍后会更仔细地阅读它,因为我的头现在要爆炸了,哈哈。再次感谢你,你是个天才。
猜你喜欢
  • 1970-01-01
  • 2018-04-14
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
相关资源
最近更新 更多