JavaScript сравнение массивов объектов
Помогите пожалуйста, бьюсь уже третий день.
У меня два массива в которых содержатся объекты.
// Массив №1. В нём содержаться все услуги и количество вложений услуг может быть любое
let allService = [
{
"Name": "1. Услуга №1",
"Code": "1",
"Items": {
"Service": [
{
"Name": "1.1 Услуга №1. шаг 1",
"Code": "8"
},
{
"Name": "1.2 Услуга №1. шаг 2",
"Code": "9"
},
{
"Name": "1.3 Услуга №1 шаг 3",
"Code": "10"
}
]
}
},
{
"Name": "Услуга №2",
"Code": "2"
},
{
"Name": "Услуга №3",
"Code": "3"
},
{
"Name": "Услуга №4",
"Code": "4"
},
{
"Name": "Услуга №5",
"Code": "5"
},
{
"Name": "Услуга №6",
"Code": "6"
},
{
"Name": "7. Услуга 7",
"Code": "7",
"Items": {
"Service": {
"Name": "7.1 Услуга 7 шаг 1",
"Code": "11",
"Items": {
"Service": {
"Name": "7.1.1 Услуга 7.1.1",
"Code": "12"
}
}
}
}
}
]
// Массив №2. В нём содержаться МОИ услуги.
let myService = [
{Service: '8'},
{Service: '9'},
{Service: '10'}
];
Подскажите, как мне из массива "allService" получить новый массив "notMyService" в котором будут все услуги за исключением тех что есть в массиве "myService". При условии, что значение Code из массива allService === значению Service из массива myService. Понимаю, что здесь нужна рекурсия, но никак не могу написать что-то более менее рабочее.
P.S. В идеале на выходе получить линейный структуру. Т.е. что-то типо такого
notMyService = [
{Code: "2", Name: "Услуга №2"},
{Code: "3", Name: "Услуга №3"},
{Code: "4", Name: "Услуга №4"},
{Code: "5", Name: "Услуга №5"},
{Code: "6", Name: "Услуга №6"},
{Code: "12", Name: "7.1.1 Услуга 7.1.1"},
]
Спасибо!
Ответы (2 шт):
Не универсальное решение, но решение.
let allService = [{
"Name": "1. Услуга №1",
"Code": "1",
"Items": {
"Service": [{
"Name": "1.1 Услуга №1. шаг 1",
"Code": "8"
},
{
"Name": "1.2 Услуга №1. шаг 2",
"Code": "9"
},
{
"Name": "1.3 Услуга №1 шаг 3",
"Code": "10"
}
]
}
},
{
"Name": "Услуга №2",
"Code": "2"
},
{
"Name": "Услуга №3",
"Code": "3"
},
{
"Name": "Услуга №4",
"Code": "4"
},
{
"Name": "Услуга №5",
"Code": "5"
},
{
"Name": "Услуга №6",
"Code": "6"
},
{
"Name": "7. Услуга 7",
"Code": "7",
"Items": {
"Service": {
"Name": "7.1 Услуга 7 шаг 1",
"Code": "11",
"Items": {
"Service": {
"Name": "7.1.1 Услуга 7.1.1",
"Code": "12"
}
}
}
}
}
];
let myService = [{
Service: '8'
},
{
Service: '9'
},
{
Service: '10'
}
];
function flattenServices(services, servicesToExclude) {
const result = [];
services.forEach(service => {
if (servicesToExclude.some(s => s.Service === service.Code)) {
return;
}
result.push(service);
const childService = service.Items?.Service;
if (childService) {
if (Array.isArray(childService)) {
const resultChild = flattenServices(childService, servicesToExclude);
result.push(...resultChild);
} else if (typeof childService === 'object') {
const resultChild = flattenServices([childService], servicesToExclude);
result.push(...resultChild);
}
}
});
return result;
}
const flatten = flattenServices(allService, myService);
console.log(flatten);
В итоге задачу можно свести к поиску листовых узлов (узлов без дочерних элементов) и выборке из них тех, которые подходят под условия.
Для поиска листовых узлов удобно воспользоваться функцией-генератором
function* lists(tree){
for(const node of tree){
if (!node.Items?.Service) yield node; // если нет детей узел листовой - возвращаем его
else yield* lists([].concat(node.Items.Service)); // иначе спускаемся на уровень вниз
}
}
Далее, достаточно просто отфильтровать полученный список узлов, например, с помощью той же функции-генератора
function* filter(nodes, exclude){
for(const node of nodes){ // бежим по коллекции
if(!exclude.some(e => e.Service == node.Code)) yield node; // если узел не надо исключать - возвращаем его
}
}
В итоге код может выглядеть так:
let allService = [
{
"Name": "1. Услуга №1",
"Code": "1",
"Items": {
"Service": [
{
"Name": "1.1 Услуга №1. шаг 1",
"Code": "8"
},
{
"Name": "1.2 Услуга №1. шаг 2",
"Code": "9"
},
{
"Name": "1.3 Услуга №1 шаг 3",
"Code": "10"
}
]
}
},
{
"Name": "Услуга №2",
"Code": "2"
},
{
"Name": "Услуга №3",
"Code": "3"
},
{
"Name": "Услуга №4",
"Code": "4"
},
{
"Name": "Услуга №5",
"Code": "5"
},
{
"Name": "Услуга №6",
"Code": "6"
},
{
"Name": "7. Услуга 7",
"Code": "7",
"Items": {
"Service": {
"Name": "7.1 Услуга 7 шаг 1",
"Code": "11",
"Items": {
"Service": {
"Name": "7.1.1 Услуга 7.1.1",
"Code": "12"
}
}
}
}
}
]
// Массив №2. В нём содержаться МОИ услуги.
let myService = [
{Service: '8'},
{Service: '9'},
{Service: '10'}
];
function* lists(tree){
for(const node of tree){
if (!node.Items?.Service) yield node;
else yield* lists([].concat(node.Items.Service));
}
}
function* filter(nodes, exclude){
for(const node of nodes){
if(!exclude.some(e => e.Service == node.Code)) yield node;
}
}
console.log([...filter(lists(allService), myService)])