【问题标题】:Remove nested array object based on id and type?删除基于 id 和类型的嵌套数组对象?
【发布时间】:2020-06-30 01:52:33
【问题描述】:

给定一个嵌套的餐点数组,我们正在尝试删除基于 idmealType 组合的嵌套对象。我们从 2 个嵌套的 breakfast 餐开始,如果两者都被删除,我们正在尝试完全删除父键,因为它现在是空的。

这是我们目前的代码:

var mealsList = {
    "menuGroup1": [
    {
      "id": "b1",
      "menuId": "FRPUbgmMiaNH",
      "title": "Eggs",
      "mealType": "breakfast"
    }, {
      "id": "b2",
      "menuId": "FRPUbgmMiaNH",
      "title": "Sandwich",
      "mealType": "breakfast"
    }
  ],
  "menuGroup2": [
    {
      "id": "b2",
      "menuId": "FRPUbgmMiaNH",
      "title": "Fruits",
      "mealType": "snack"
    }
  ]
};

console.log(mealsList);

const removeItem = (id, mealType) => {
  // pseudocode
  // mealsList.*.where("id" == id && "mealType" == mealType).remove();
}

// Remove breakfast with id and meal_type
// removeItem(id, mealType)
removeItem('b1', 'breakfast');
console.log('removed b1 breakfast, mealsList should only contain b2 object');
console.log(mealsList);

removeItem('b2', 'breakfast');
console.log('removed b2 breakfast, mealsList should only contain menuGroup2, as menuGroup1 is now empty');
console.log(mealsList);

问题是我们试图在不明确传递menuGroupX 的情况下删除removeItem 中的嵌套餐对象,相反,我们试图基于id 和@987654330 定位嵌套的mealsList 对象@。伪代码使用* 来表明这一点。

console.log 语句显示了mealsList 应如何呈现在它们下的预期结果。

我们正在寻找一种简短而甜蜜的东西,最好是单衬里,即使这意味着为了简单起见使用 lodash 解决方案。

Here is the fiddle(JS 选项卡中的代码)

知道在removeItem 中放置什么而不是伪代码以使mealsList 删除特定项目吗?

【问题讨论】:

  • 我不知道将 JS 对象创建为 JSON 是否是一种好习惯。

标签: javascript arrays lodash


【解决方案1】:

这是一个纯 JavaScript 解决方案,它遍历 mealsList 的键,通过 idmealType 过滤,然后将结果数组的长度与 0 进行比较;如果为 0,则从 mealsList 中删除该密钥:

var mealsList = {
  "menuGroup1": [{
    "id": "b1",
    "menuId": "FRPUbgmMiaNH",
    "title": "Eggs",
    "mealType": "breakfast"
  }, {
    "id": "b2",
    "menuId": "FRPUbgmMiaNH",
    "title": "Sandwich",
    "mealType": "breakfast"
  }],
  "menuGroup2": [{
    "id": "b2",
    "menuId": "FRPUbgmMiaNH",
    "title": "Fruits",
    "mealType": "snack"
  }]
};

console.log(mealsList);

const removeItem = (id, mealType) => {
  Object.keys(mealsList).forEach(k => (mealsList[k] = mealsList[k].filter(m => m.id != id || m.mealType != mealType)).length == 0 && delete mealsList[k]);
}

// Remove breakfast with id and meal_type
// removeItem(id, mealType)
removeItem('b1', 'breakfast');
console.log('removed b1 breakfast, mealsList should only contain b2 object');
console.log(mealsList);

removeItem('b2', 'breakfast');
console.log('removed b2 breakfast, mealsList should only contain menuGroup2, as menuGroup1 is now empty');
console.log(mealsList);

【讨论】:

  • 我喜欢它;令人惊讶的可读性。如果 OP 将饭菜列表更改为 mL,则可以缩短。
  • 非常漂亮和干净的一个带有纯 JS 的衬里,非常易读,效果很好!谢谢!
  • @Wonka 不用担心 - 我很高兴能帮上忙。
【解决方案2】:

您可以使用 lodash 的 _.mapValues() 映射对象中的数组键,以排除包含传递给您的函数的 idmealType 的任何对象。然后,您可以使用 _.omitBy() 删除任何具有空数组作为其值的键:

let mealsList = { "menuGroup1": [ { "id": "b1", "menuId": "FRPUbgmMiaNH", "title": "Eggs", "mealType": "breakfast" }, { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Sandwich", "mealType": "breakfast" } ], "menuGroup2": [ { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Fruits", "mealType": "snack" } ] };

const removeItem = (id, mealType) => {
  mealsList = _.omitBy(_.mapValues(mealsList, arr => _.filter(arr, o => o.id !== id || o.mealType !== mealType)), _.isEmpty);
}

removeItem('b1', 'breakfast');
console.log(mealsList);
removeItem('b2', 'breakfast');
console.log(mealsList);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

一种普通的方法可能是首先将您的mealsList 转换为一个条目数组,然后使用.map().filter() 过滤整个内部数组。然后,完成后,您可以使用Object.fromEntries() 重建对象:

let mealsList = { "menuGroup1": [ { "id": "b1", "menuId": "FRPUbgmMiaNH", "title": "Eggs", "mealType": "breakfast" }, { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Sandwich", "mealType": "breakfast" } ], "menuGroup2": [ { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Fruits", "mealType": "snack" } ] };

const removeItem = (id, mealType) => {
  mealsList = Object.fromEntries(
    Object.entries(mealsList).map(([k,vals]) => [k, vals.filter(o => o.id !== id || o.mealType !== mealType)]).filter(([, {length}]) => length > 0)
  );
}

removeItem('b1', 'breakfast');
console.log(mealsList);
removeItem('b2', 'breakfast');
console.log(mealsList);

上述更兼容浏览器的版本(没有 Object.fromEntries()):

let mealsList = { "menuGroup1": [ { "id": "b1", "menuId": "FRPUbgmMiaNH", "title": "Eggs", "mealType": "breakfast" }, { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Sandwich", "mealType": "breakfast" } ], "menuGroup2": [ { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Fruits", "mealType": "snack" } ] };

const removeItem = (id, mealType) => {
  mealsList = Object.assign({},
    ...Object.entries(mealsList).map(([k,vals]) => [k, vals.filter(o => o.id !== id || o.mealType !== mealType)]).filter(([, {length}]) => length > 0).map(([key, val]) => ({[key]: val}))
  );
}

removeItem('b1', 'breakfast');
console.log(mealsList);
removeItem('b2', 'breakfast');
console.log(mealsList);

理想情况下,您的mealsList 应该是一个数组,因为它是一个列表,这样可以更直接地处理您的数据。

【讨论】:

  • 感谢您的双向展示,点赞!我接受了另一个答案,因为它是一个非常干净的纯 JS 衬垫。
【解决方案3】:

您可以通过reducefilter 进行操作。

let mealsList = { "menuGroup1": [ { "id": "b1", "menuId": "FRPUbgmMiaNH", "title": "Eggs", "mealType": "breakfast" }, { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Sandwich", "mealType": "breakfast" } ], "menuGroup2": [ { "id": "b2", "menuId": "FRPUbgmMiaNH", "title": "Fruits", "mealType": "snack" } ] };

const  removeItem = (id, mealType) => {
  mealsList = Object.entries(mealsList )
  .reduce((output, [key, value]) => {
    const filterDetail = value.filter(val => (val.id!==id || val.mealType!==mealType))
    if(filterDetail.length> 0) output[key] = filterDetail;
    return output;
  }, {});
};

removeItem('b1', 'breakfast');
console.log(mealsList);
removeItem('b2', 'breakfast');
console.log(mealsList);

【讨论】:

  • 在这种情况下reduce 有什么好处?
猜你喜欢
  • 2020-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 2017-04-25
  • 1970-01-01
  • 2021-07-03
相关资源
最近更新 更多