【问题标题】:Mapping an array of objects containing an empty array as property ignores the whole object将包含空数组的对象数组映射为属性会忽略整个对象
【发布时间】:2020-08-30 14:07:38
【问题描述】:

我有一个对象数组 -

let initialArr = [
  {
    "id": 1,
    "name": "product name",
    "product_details": [
      {
        "id": 1,
        "details": "some details"
      }
    ],
    "subscriptions": [
      {
        "id": 1,
        "subs": "7 days"
      },
      {
        "id": 2,
        "subs": "15 days"
      }
    ]
  },
  {
    "id": 2,
    "name": "product name 2",
    "product_details": [
      {
        "id": 2,
        "details": "some details 2"
      }
    ],
    "subscriptions": [
      {
        "id": 1,
        "subs": "7 days"
      },
      {
        "id": 2,
        "subs": "15 days"
      }
    ]
  },
  {
    "id": 3,
    "name": "product name 3",
    "product_details": [
      {
        "id": 3,
        "details": "some details 3"
      }
    ],
    "subscriptions": []
  }
]

这就是我想要实现的-

[
  {
    "id": 1,
    "name": "product name",
    "detailsId" : 1,
    "details": "some details"
    "subsId": 1,
    "subs": "7 days"
  },
  {
    "id": 1,
    "name": "product name",
    "detailsId" : 1,
    "details": "some details"
    "subsId": 2,
    "subs": "15 days"
  },
  {
    "id": 2,
    "name": "product name 2",
    "detailsId" : 2,
    "details": "some details 2"
    "subsId": 1,
    "subs": "7 days"
  },
  {
    "id": 2,
    "name": "product name 2",
    "detailsId" : 2,
    "details": "some details 2"
    "subsId": 2,
    "subs": "15 days"
  },
  {
    "id": 3,
    "name": "product name 3",
    "detailsId" : 3,
    "details": "some details 3"
  }
]

这就是我所做的-

initialArr.map(e => {
  e.product_details.map(p =>{
   e.subscriptions.map(s => {
      newArr.push({
        id: e.id,
        name: e.name,
        detailsId: p.id,
        details: p.details,
        subsId: s.id,
        subs:s.subs        
      }); 
   }); 
  })
})

如果订阅数组不为空,则此方法有效。如果对于某些产品,订阅数组为空,则该产品不会被推送到数组中。在我无法弄清楚如何解决它。

第三个产品未推送到新数组中。这就是我得到的 -

[
  {
    "id": 1,
    "name": "product name",
    "detailsId" : 1,
    "details": "some details"
    "subsId": 1,
    "subs": "7 days"
  },
  {
    "id": 1,
    "name": "product name",
    "detailsId" : 1,
    "details": "some details"
    "subsId": 2,
    "subs": "15 days"
  },
  {
    "id": 2,
    "name": "product name 2",
    "detailsId" : 2,
    "details": "some details 2"
    "subsId": 1,
    "subs": "7 days"
  },
  {
    "id": 2,
    "name": "product name 2",
    "detailsId" : 2,
    "details": "some details 2"
    "subsId": 2,
    "subs": "15 days"
  }
]

注意:虽然同一产品在新数组中重复了两次,但这是要求——产品根据订阅数组的“subs”属性。

假设我有更多的数组,例如除了“订阅”之外的“自定义”、“订单”等,我还希望推送这些数组的数据,这是对多个数组执行的正确方法吗?

【问题讨论】:

  • 在 bock 语句中,如果没有 return map(...,则不会返回任何数组。
  • 您在product_details中是否一直只有一种产品?
  • product_details 包含产品的详细信息,即产品“产品名称”的详细信息。所以它总是有一个产品细节。我不明白你的第一条评论

标签: javascript arrays json object


【解决方案1】:

假设数组 product_details 总是有 1 个元素及其数据,这是一个解决方案。
使用Array#reduce 来累积新的结果数组。使用所有数据创建 foreach 元素一个新的临时对象。如果订阅数组为空,则将此临时对象推送到您的累积结果数组。否则使用Array#forEach 来遍历您的订阅。对于每个订阅,请使用 Object.assign 制作临时对象的副本。添加订阅数据并将其推送到结果数组。

const initialArr = [{ id: 1, name: "product name", product_details: [{ id: 1, details: "some details" }], subscriptions: [{ id: 1, subs: "7 days" }, { id: 2, subs: "15 days" }] }, { id: 2, name: "product name 2", product_details: [{ id: 2, details: "some details 2" }], subscriptions: [{ id: 1, subs: "7 days" }, { id: 2, subs: "15 days" }] }, { id: 3, name: "product name 3", product_details: [{ id: 3, details: "some details 3" }], subscriptions: [] }];

let res = initialArr.reduce((acc, cur) => {
    let temp = {
        id: cur.id,
        name: cur.name,
        detailsId: cur.product_details[0].id,
        details: cur.product_details[0].details
    }
    if (!cur.subscriptions.length)
        acc.push(temp);
    else {
        cur.subscriptions.forEach(subs => {
            let tempSub = Object.assign({}, temp);
            tempSub.subsId = subs.id;
            tempSub.subs = subs.subs;
            acc.push(tempSub);
        })
    }
    return acc;
}, []);

console.log(res);

这里是一个没有reduce 而是forEach 的版本:

const initialArr = [{ id: 1, name: "product name", product_details: [{ id: 1, details: "some details" }], subscriptions: [{ id: 1, subs: "7 days" }, { id: 2, subs: "15 days" }] }, { id: 2, name: "product name 2", product_details: [{ id: 2, details: "some details 2" }], subscriptions: [{ id: 1, subs: "7 days" }, { id: 2, subs: "15 days" }] }, { id: 3, name: "product name 3", product_details: [{ id: 3, details: "some details 3" }], subscriptions: [] }];

let acc = [];
initialArr.forEach(cur => {
    let temp = {
        id: cur.id,
        name: cur.name,
        detailsId: cur.product_details[0].id,
        details: cur.product_details[0].details
    }
    if (!cur.subscriptions.length)
        acc.push(temp);
    else {
        cur.subscriptions.forEach(subs => {
            let tempSub = Object.assign({}, temp);
            tempSub.subsId = subs.id;
            tempSub.subs = subs.subs;
            acc.push(tempSub);
        })
    }
});

console.log(acc);

【讨论】:

  • 谢谢。不使用reduce是否可以做到这一点?
  • 是的,当然,我在帖子末尾的其他解决方案下方添加了它。
  • 很高兴为您提供帮助。顺便提一句。您现在拥有足够的声誉,可以对答案和问题进行投票,而不仅仅是接受它们。
  • 我投了赞成票,但还没有注册。再做一次。
  • 是的,它可以与map 一起使用,但这并不是打算以这种方式使用 map,因为 map 通过内部计算从起始数组中创建了一个新数组。此处未使用(内部不存在任何返回),因此结果数组由 3 个未定义值组成。 注意: 如果您有一个包含 n 个元素的数组并且结果由一个相同长度的数组组成,则通常最好使用 Map。
【解决方案2】:

您可以检查subscription 的长度并返回一个对象,而不是映射数组。

const
    data = [{ id: 1, name: "product name", product_details: [{ id: 1, details: "some details" }], subscriptions: [{ id: 1, subs: "7 days" }, { id: 2, subs: "15 days" }] }, { id: 2, name: "product name 2", product_details: [{ id: 2, details: "some details 2" }], subscriptions: [{ id: 1, subs: "7 days" }, { id: 2, subs: "15 days" }] }, { id: 3, name: "product name 3", product_details: [{ id: 3, details: "some details 3" }], subscriptions: [] }],
    result = data.flatMap(({ product_details: [{ id: detailsId, details }], subscriptions, ...o }) => subscriptions.length
        ? subscriptions.map(({ id: subsId, subs }) => ({ ...o, detailsId, details, subsId, subs }))
        : ({ ...o, detailsId, details })
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案3】:

    您需要明确处理该案例:

    if (e.subscriptions.length === 0) {
      newArr.push({ ... }
    } else {
      e.subscriptions.map(...)
    }
    

    您也应该使用forEach 而不是map

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-11
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      • 2020-10-02
      • 2022-11-24
      • 2021-02-15
      • 2021-12-25
      相关资源
      最近更新 更多