Каков наилучший способ пройти через этот javscript - PullRequest
3 голосов
/ 11 июля 2019

У меня есть основной список элементов, который является вложенным массивом объектов, у меня также есть выбранный список ..

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 и выбранный список, я бы хотел получить производный список который должен выглядеть следующим образом

[{
  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, значением которого будет соответствующее значение item_list в массиве selected_list.

Разница в masterList и selectedList заключается в том, что свойство item_list в selectedList является подмножеством 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"]
  }]
}]

которого нет в selectedList.

Как мне этого добиться?

Редактировать: в настоящее время я делаю это так

masterList.forEach(cat_met_item => {
  selectedList.forEach(filled_cat_met_item => {
    if (cat_met_item.category_id === filled_cat_met_item.category_id) {
      cat_met_item.meta_list.forEach(met_item => {
        filled_cat_met_item.meta_list.forEach(filled_met_item => {
          if (met_item.id === filled_met_item.id) {
            met_item["list"] = filled_met_item["item_list"];
          }
        });
      });
    }
  });
});

Использование 4 циклов forEach. Я не нахожу свой метод эффективным и очень грязным, так есть ли лучший способ сделать это?

Ответы [ 5 ]

3 голосов
/ 15 июля 2019

Использование метода фильтра 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);
2 голосов
/ 20 июля 2019

Вдохновлен Матеушем Синиарским, генерируя желаемый результат и заменяя 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] ]
  })
})
2 голосов
/ 16 июля 2019

Вы можете использовать reduce для итерации и find для получения необходимого вам предмета. Следующий код также обрабатывает отсутствующие выбранные элементы / meta_list.

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));
2 голосов
/ 15 июля 2019

Использование 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)
1 голос
/ 17 июля 2019

Я бы просто глубоко клонировал оба объекта, используя JSON.parse(JSON.stringify(_)), а затем скопировал бы любые свойства, которые существуют в selectedList, а не в masterList, в клонированную копию объекта masterList.

Поскольку вы имеете дело со строками (из-за JSON.stringify), вы можете просто заменить item_list на sel_list, используя String#replace.

Последняя проблема теперь заключается в сопоставлении элементов массива masterList с соответствующими в selectedList. Одним из способов было бы просто использовать index, но это, очевидно, не очень безопасно или надежно. Я бы порекомендовал предоставить функцию для метода, который выполняет объединение, который будет принимать элемент из каждого массива и определит, являются ли они equal. Эта функция также должна понимать, на какой массив вы ссылаетесь (т.е. masterList, meta_list, item_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;
  }
}));
...