Я хочу преобразовать объект javascript, который ссылается друг на друга по его атрибуту,
Говорит, что у меня есть этот объект
{
apple: {
banana: [1,2,3],
cherry: [4,5,6],
},
banana: {
date: [7],
cherry: [8,9],
elderberry: [10, 11],
},
cherry: {
date: [7],
fig: [12,13],
},
date: {
fig: [11,14],
},
},
И я хочу превратить этот объект в этот
{
apple: {
banana: [1,2,3],
cherry: [4,5,6, 8,9],
date: [7],
elderberry: [10, 11],
fig: [11,14, 12,13],
},
banana: {
cherry: [8,9],
elderberry: [10, 11],
fig: [11,14, 12,13],
date: [7],
},
cherry: {
date: [7],
fig: [11,14, 12,13],
},
date: {
fig: [11,14],
},
}
В этом примере атрибут вишни и яблока имеет [4,5,6, 8,9], [4,5,6] происходит от яблока, а [8, 9] происходит от банана, потому что яблоко относится к банану, а банан относится к вишне, поэтому они будут объединены в [4,5,6, 8,9 ]
а также окончательный массив на самом деле является уникальным значением
Таким образом, идея состоит в том, что он будет рекурсивно объединять другие значения компонентов, используя lodash или другую библиотеку.
извините обновлю пример
Что происходит, когда в окончательных массивах есть повторяющиеся значения? Не могли бы вы осветить это также в своем примере?
на самом деле конечный массив всегда уникален, уже обновил пример, спасибо :)
Примеры, в которых для названий свойств используются одиночные буквы, значительно усложняют обсуждение проблемы («С — это свойство а, или с — свойство b»). Гораздо лучше использовать уникальные слова.
@HereticMonkey обновлен :)
Вы можете использовать вложенный подход с рекурсивной функцией с маркером выхода.
const
iter = (object, key, target, sub) => Object
.keys(object[key] || {})
.reduce((o, k) => {
o[k] = Array.from(new Set([...(o[k] || []), ...object[key][k]]));
return sub
? iter(object, k, o)
: o;
}, target);
var object = { apple: { banana: [1, 2, 3], cherry: [4, 5, 6], }, banana: { date: [7], cherry: [8, 9], elderberry: [10, 11], }, cherry: { date: [7], fig: [12, 13], }, date: { fig: [11, 14] } },
result = Object.keys(object).reduce((o, k) => {
iter(object, k, o[k] = o[k] || {}, true);
return o;
}, {});
console.info(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Вы можете использовать рекурсивный подход для каждого подраздела (функция addKeys
), используя Object.entries()
с Array.reduce()
и передавая текущие существующие ключи всякий раз, когда вы снова вызываете функцию, чтобы избежать вечного цикла.
Затем вы можете уменьшить записи объекта data
и вызвать addKeys
для каждого ключа.
const data = {"apple":{"banana":[1,2,3],"cherry":[4,5,6]},"banana":{"date":[7],"cherry":[8,9],"elderberry":[10,11]},"cherry":{"date":[7],"fig":[12,13]},"date":{"fig":[11,14]}}
const addKeys = (obj = {}, existing = []) =>
Object.entries(obj)
.reduce((r, [k, v]) =>
existing.includes(k) ? r :
({
...r,
[k]: v,
...addKeys(data[k], [...existing, k, ...Object.keys(r)]),
})
, {})
// iterate the data object and rebuild it by adding keys to each sub-key
const result = Object.entries(data)
.reduce((r, [k, v]) => {
r[k] = addKeys(v);
return r;
}, {})
console.info(result)
Я бы сначала создал структуру, которая хранит противоположные отношения, то есть от дочернего к родительскому.
Затем для каждой пары ключ/массив следуем по пути (через новую структуру) вверх к своим предкам и для каждого из них добавляем там массив к тому же ключу. Я выбрал обход с использованием явной переменной стека для этого, но он будет работать так же хорошо с рекурсивным обходом DFS.
Наконец, снова посетите все массивы, чтобы удалить дубликаты.
function complete(data) {
// Create child-parent relationships:
const parents = {};
for (const parent in data) {
for (const child in data[parent]) {
(parents[child] = parents[child] || []).push(parent);
}
}
// Tree traveral to copy child array into same key in ancestors
const result = {};
for (const parent in data) {
for (const child in data[parent]) {
const arr = data[parent][child];
const visited = new Set;
const stack = [parent];
while (stack.length) {
const node = stack.pop();
if (visited.has(node)) continue;
visited.add(node);
((result[node] = result[node] || {})[child] = result[node][child] || []).push(...arr);
stack.push(...parents[node] || []);
}
}
}
// Remove duplicate values from the arrays
for (const parent in result) {
for (const child in result[parent]) {
result[parent][child] = [...new Set(result[parent][child])];
}
}
return result;
}
// Example call with data from the question:
const data = {apple: {banana: [1,2,3],cherry: [4,5,6],},banana: {date: [7],cherry: [8,9],elderberry: [10, 11],},cherry: {date: [7],fig: [12,13],},date: {fig: [11,14],},};
const result = complete(data);
console.info(result);
Вы говорите рекурсивно, но похоже, что ваш пример выглядит только до определенной глубины. Например: из
a
вb
, вd
мы получаемf: [11, 14]
. Так почему же этого нет вf
спискеa
?