循环浏览此脚本的最佳方法是什么

时间:2019-07-11 09:26:48

标签: javascript arrays loops object foreach

我有一个项目的主列表,该列表是对象的嵌套数组,我也有一个选定的列表。.

let masterList = [{
  category_id: 1,
  meta_list: [{
    name: "Cuisine",
    id: "QWEQWEQWE",
    is_multiselect: false,
    item_list: ["Arabian", "Indian"]
  }, {
    name: "Cost for Two",
    id: "SFDFSDASDASDASD",
    is_multiselect: true,
    item_list: [
      "AED 0 - 100",
      "AED 100 - 200",
      "Greater Than AED 200"
    ]
  }]
}, {
  category_id: 2,
  meta_list: [{
    name: "Cat 2",
    id: "cat2",
    is_multiselect: false,
    item_list: ["cat 2 1", "cat 2 2"]
  }, {
    name: "cuisine 2",
    id: "cui2",
    is_multiselect: true,
    item_list: ["cu1", "cu2"]
  }]
}];

let selectedList = [{
  category_id: 1,
  meta_list: [{
    name: "Cuisine",
    id: "QWEQWEQWE",
    is_multiselect: false,
    item_list: ["Arabian"]
  }, {
    name: "Cost for Two",
    id: "SFDFSDASDASDASD",
    is_multiselect: true,
    item_list: [
      "AED 100 - 200",
      "Greater Than AED 200"
    ]
  }]
}, {
  category_id: 2,
  meta_list: [{
    name: "cuisine 2",
    id: "cui2",
    is_multiselect: true,
    item_list: ["cu1"]
  }]
}];

使用masterList和选择的列表,我希望有一个namedList 必须看起来像这样

[{
  category_id: 1,
  meta_list: [{
    name: "Cuisine",
    id: "QWEQWEQWE",
    is_multiselect: false,
    item_list: ["Arabian", "Indian"],
    sel_list: ["Arabian"]
  }, {
    name: "Cost for Two",
    id: "SFDFSDASDASDASD",
    is_multiselect: true,
    item_list: [
      "AED 0 - 100",
      "AED 100 - 200",
      "Greater Than AED 200"
    ],
    sel_list: [
      "AED 100 - 200",
      "Greater Than AED 200"
    ]
  }]
}, {
  category_id: 2,
  meta_list: [{
    name: "Cat 2",
    id: "cat2",
    is_multiselect: false,
    item_list: ["cat 2 1", "cat 2 2"],
    sel_list: ["cat 2 2"]
  }, {
    name: "cuisine 2",
    id: "cui2",
    is_multiselect: true,
    item_list: ["cu1", "cu2"],
    sel_list: ["cu1"]
  }]
}];

我希望具有与masterList相同的项目和结构的期望列表,除了它具有另一个属性sel_list之外,该属性的值将是{{1 }}数组。

item_listselected_list的区别在于masterList中的selectedList属性是item_listselectedList的子集

如您在示例中所见,item_list也可以有一个附加项目

masterList

masterList

不在{ name: "Cat 2", id: "cat2", is_multiselect: false, item_list: ["cat 2 1", "cat 2 2"], }中。

我该如何实现?

编辑:我目前正在这样做

[{
  category_id: 1,
  meta_list: [{
    name: "Cuisine",
    id: "QWEQWEQWE",
    is_multiselect: false,
    item_list: ["Arabian", "Indian"],
    sel_list: ["Arabian"]
  }, {
    name: "Cost for Two",
    id: "SFDFSDASDASDASD",
    is_multiselect: true,
    item_list: [
      "AED 0 - 100",
      "AED 100 - 200",
      "Greater Than AED 200"
    ],
    sel_list: [
      "AED 100 - 200",
      "Greater Than AED 200"
    ]
  }]
}, {
  category_id: 2,
  meta_list: [{
    name: "Cat 2",
    id: "cat2",
    is_multiselect: false,
    item_list: ["cat 2 1", "cat 2 2"],
    sel_list: ["cat 2 2"]
  }, {
    name: "cuisine 2",
    id: "cui2",
    is_multiselect: true,
    item_list: ["cu1", "cu2"],
    sel_list: ["cu1"]
  }]
}]

使用4个forEach循环。我发现我的方法效率不高而且非常凌乱,所以有更好的方法吗?

5 个答案:

答案 0 :(得分:4)

使用json过滤方法:

let masterList = [
                {
                    category_id: 1,
                    meta_list: [
                        {
                            name: "Cuisine",
                            id: "QWEQWEQWE",
                            is_multiselect: false,
                            item_list: ["Arabian", "Indian"]
                        },

                        {
                            name: "Cost for Two",
                            id: "SFDFSDASDASDASD",
                            is_multiselect: true,
                            item_list: [
                                "AED 0 - 100",
                                "AED 100 - 200",
                                "Greater Than AED 200"
                            ]
                        }
                    ]
                },
                {
                    category_id: 2,
                    meta_list: [
                        {
                            name: "Cat 2",
                            id: "cat2",
                            is_multiselect: false,
                            item_list: ["cat 2 1", "cat 2 2"]
                        },

                        {
                            name: "cuisine 2",
                            id: "cui2",
                            is_multiselect: true,
                            item_list: ["cu1", "cu2"]
                        }
                    ]
                }
            ];

      let selectedList = [
                        {
                            category_id: 1,
                            meta_list: [
                                {
                                    name: "Cuisine",
                                    id: "QWEQWEQWE",
                                    is_multiselect: false,
                                    item_list: ["Arabian"]
                                },
                                {
                                    name: "Cost for Two",
                                    id: "SFDFSDASDASDASD",
                                    is_multiselect: true,
                                    item_list: [
                                        "AED 100 - 200",
                                        "Greater Than AED 200"
                                    ]
                                }
                            ]
                        },
                        {
                            category_id: 2,
                            meta_list: [
                                {
                                    name: "cuisine 2",
                                    id: "cui2",
                                    is_multiselect: true,
                                    item_list: ["cu1"]
                                }
                            ]
                        }
                    ];

masterList.forEach(cat_met_item => {
  var obj = selectedList.filter(function (el) {
    return cat_met_item.category_id === el.category_id;
    
  })
  cat_met_item.meta_list.forEach(met_item => {
      var selObj = obj[0].meta_list.filter(function (el) {
      return met_item.id === el.id;
    });
    if (selObj[0]) {
      met_item['sel_list'] = selObj[0].item_list;
    }
    else {
      met_item['sel_list'] = met_item.item_list[met_item.item_list.length - 1];
    }
  });
});

console.log(masterList);

答案 1 :(得分:2)

在这种情况下,使用Array.prototype.find()可能更好。

let masterList = [
                {
                    category_id: 1,
                    meta_list: [
                        {
                            name: "Cuisine",
                            id: "QWEQWEQWE",
                            is_multiselect: false,
                            item_list: ["Arabian", "Indian"]
                        },

                        {
                            name: "Cost for Two",
                            id: "SFDFSDASDASDASD",
                            is_multiselect: true,
                            item_list: [
                                "AED 0 - 100",
                                "AED 100 - 200",
                                "Greater Than AED 200"
                            ]
                        }
                    ]
                },
                {
                    category_id: 2,
                    meta_list: [
                        {
                            name: "Cat 2",
                            id: "cat2",
                            is_multiselect: false,
                            item_list: ["cat 2 1", "cat 2 2"]
                        },

                        {
                            name: "cuisine 2",
                            id: "cui2",
                            is_multiselect: true,
                            item_list: ["cu1", "cu2"]
                        }
                    ]
                }
            ];

      let selectedList = [
                        {
                            category_id: 1,
                            meta_list: [
                                {
                                    name: "Cuisine",
                                    id: "QWEQWEQWE",
                                    is_multiselect: false,
                                    item_list: ["Arabian"]
                                },
                                {
                                    name: "Cost for Two",
                                    id: "SFDFSDASDASDASD",
                                    is_multiselect: true,
                                    item_list: [
                                        "AED 100 - 200",
                                        "Greater Than AED 200"
                                    ]
                                }
                            ]
                        },
                        {
                            category_id: 2,
                            meta_list: [
                                {
                                    name: "cuisine 2",
                                    id: "cui2",
                                    is_multiselect: true,
                                    item_list: ["cu1"]
                                }
                            ]
                        }
                    ];

masterList.forEach(master_item => {
  let select_item = selectedList.find((el) => master_item.category_id === el.category_id);
  master_item.meta_list.forEach(met_item => {
    let select_meta = select_item.meta_list.find((el) => met_item.id === el.id);
    if (select_meta) {
      met_item.sel_list = select_meta.item_list;
    } else {
      met_item.sel_list = [met_item.item_list[met_item.item_list.length - 1]];
    }
  });
});
console.log(masterList)

答案 2 :(得分:2)

您可以使用reduce进行迭代,并使用find获得所需的物品。以下代码还处理丢失的选定/元列表项。

const exampleMasterList = [
  {
    category_id: 1,
    meta_list: [
      {
        name: 'Cuisine',
        id: 'QWEQWEQWE',
        is_multiselect: false,
        item_list: ['Arabian', 'Indian']
      },

      {
        name: 'Cost for Two',
        id: 'SFDFSDASDASDASD',
        is_multiselect: true,
        item_list: ['AED 0 - 100', 'AED 100 - 200', 'Greater Than AED 200']
      }
    ]
  },
  {
    category_id: 2,
    meta_list: [
      {
        name: 'Cat 2',
        id: 'cat2',
        is_multiselect: false,
        item_list: ['cat 2 1', 'cat 2 2']
      },

      {
        name: 'cuisine 2',
        id: 'cui2',
        is_multiselect: true,
        item_list: ['cu1', 'cu2']
      }
    ]
  }
];

const exampleSelectedList = [
  {
    category_id: 1,
    meta_list: [
      {
        name: 'Cuisine',
        id: 'QWEQWEQWE',
        is_multiselect: false,
        item_list: ['Arabian']
      },
      {
        name: 'Cost for Two',
        id: 'SFDFSDASDASDASD',
        is_multiselect: true,
        item_list: ['AED 100 - 200', 'Greater Than AED 200']
      }
    ]
  },
  {
    category_id: 2,
    meta_list: [
      {
        name: 'cuisine 2',
        id: 'cui2',
        is_multiselect: true,
        item_list: ['cu1']
      }
    ]
  }
];

const getDesiredList = (masterList, selectedList) =>
  masterList.reduce((a, c) => {
    const selectedItem = selectedList.find(ent => ent.category_id === c.category_id);

    return [
      ...a,
      {
        ...c,
        meta_list: c.meta_list.reduce((a2, c2) => {
          const meta_list_item = selectedItem && selectedItem.meta_list.find(ent => ent.id === c2.id);

          return [
            ...a2,
            {
              ...c2,
              sel_list: meta_list_item ? meta_list_item.item_list : []
            }
          ];
        }, [])
      }
    ];
  }, []);

console.log(JSON.stringify(getDesiredList(exampleMasterList, exampleSelectedList), null, 2));

答案 3 :(得分:2)

受Mateusz Siniarski的启发,同时生成所需的输出并将reduce替换为map

const derivedList = masterList.map(master => {
  const selected = selectedList.find(el => el.category_id === master.category_id)
  return {
    ...master,
    meta_list: master.meta_list.map(meta => {
      const { item_list } = selected.meta_list.find(el => el.id === meta.id) || {}
      return {
        ...meta,
        sel_list: item_list || [ meta.item_list[meta.item_list.length - 1] ]
      }
    })
  }
})

变异masterList的迭代版本:

masterList.forEach(master => {
  const selected = selectedList.find(el => el.category_id === master.category_id)
  master.meta_list.forEach(meta => {
    const { item_list } = selected.meta_list.find(el => el.id === meta.id) || {}
    meta.sel_list = item_list || [ meta.item_list[meta.item_list.length - 1] ]
  })
})

答案 4 :(得分:1)

我只是使用JSON.parse(JSON.stringify(_))深度克隆两个对象,然后将selectedList而不是masterList中存在的所有属性复制到masterList对象的克隆副本中。

由于您正在处理字符串(由于JSON.stringify,因此您可以使用item_listsel_list替换为String#replace

现在的最后一个问题是将masterList的数组项与selectedList中的数组项进行匹配。一种方法是仅使用index,但这显然不是非常安全或可靠。我建议为执行合并的方法提供一个函数,该函数将接受每个数组中的一项并确定它们是否为equal。此功能还必须能够理解您所指的是哪个数组(即masterListmeta_listitem_list ...)。

这里是您问题的相当抽象的解决方案,唯一的自定义部分是最后的最后5行,它们将item_list替换为sel_list并管理数组匹配,其他所有内容均可重用。 (我已经将两个对象转换为字符串以节省垂直空间,您可以专注于解决方案,而无需向下滚动到它)。

let masterList = `[{"category_id":1,"meta_list":[{"name":"Cuisine","id":"QWEQWEQWE","is_multiselect":false,"item_list":["Arabian","Indian"]},{"name":"Cost for Two","id":"SFDFSDASDASDASD","is_multiselect":true,"item_list":["AED 0 - 100","AED 100 - 200","Greater Than AED 200"]}]},{"category_id":2,"meta_list":[{"name":"Cat 2","id":"cat2","is_multiselect":false,"item_list":["cat 2 1","cat 2 2"]},{"name":"cuisine 2","id":"cui2","is_multiselect":true,"item_list":["cu1","cu2"]}]}]`;
let selectedList = `[{"category_id":1,"meta_list":[{"name":"Cuisine","id":"QWEQWEQWE","is_multiselect":false,"item_list":["Arabian"]},{"name":"Cost for Two","id":"SFDFSDASDASDASD","is_multiselect":true,"item_list":["AED 100 - 200","Greater Than AED 200"]}]},{"category_id":2,"meta_list":[{"name":"cuisine 2","id":"cui2","is_multiselect":true,"item_list":["cu1"]}]}]`;

/**
 * Deep merges 2 objects (if a property exists for both objects then only the original will be used)
 * @param {{} | string} original Original object in object or json format
 * @param {{} | string} other Other object in object or json format
 * @param {(original: string | {}, other: string | {}) => boolean} manageList Function called to compare items in the arrays
 * @returns {{}} 
 */
function mergeJSONs(original, other, manageList) {
  original = typeof original === "string" ? original : JSON.stringify(original); // Deep clone both objects
  other = typeof other === "string" ? other : JSON.stringify(other);
  return recursiveMerge(JSON.parse(original), JSON.parse(other), manageList);
}

/**
 * Copies all the properties that exist in the `other` object to the `original` object
 * @param {{}} original Object to copy the properties to
 * @param {{}} other Object to copy the properties from
 * @param {(original: string | {}, other: string | {}) => boolean} manageList Function called to compare items in the arrays
 * @returns {{}}
 */
function recursiveMerge(original, other, manageList) {
  if (original instanceof Array) {
    if (!(other instanceof Array)) throw Error("Incompatible Types");
    var matchedList = [];
    for (var otherItem of other) {
      var originalIndex = original.findIndex(function(originalItem, index) {
        if (manageList.call(this, originalItem, otherItem) && !matchedList.includes(index)) return matchedList.push(index);
      });
      if (originalIndex === -1) original.push(otherItem);
      else if (typeof otherItem === "object") recursiveMerge(original[originalIndex], otherItem, manageList);
    }
  } else {
    if (other instanceof Array) throw Error("Incompatible Types");
    for (var key in other) {
      if (!(key in original)) original[key] = other[key];
      else if (typeof other[key] === "object") recursiveMerge(original[key], other[key], manageList);
    }
  }
  return original;
}

console.log(mergeJSONs(masterList, selectedList.replace(/"item_list":/g, "\"sel_list\":"), function(original, other) {
  if (typeof original === "string" && typeof other === "string") return original === other;
  else if (typeof original === "object" && typeof other === "object") {
    if ("category_id" in original && "category_id" in other) return original.category_id === other.category_id;
    if ("id" in original && "id" in other) return original.id === other.id;
  }
}));