#javascript #arrays #object
#javascript #массивы #объект
Вопрос:
Я хочу преобразовать объект 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],
},
}
В этом примере атрибут cherry в apple имеет [4,5,6, 8,9],
[4,5,6] исходит от apple, а [8, 9] исходит от banana, потому что apple ссылается на banana, а banana имеет ссылку на вишню, поэтому он будет объединен в [4,5,6, 8,9]
а также конечный массив на самом деле является уникальным значением
Таким образом, идея заключается в том, что он будет рекурсивно объединять другое значение компонента, использование lodash или другой библиотеки в порядке ~
Комментарии:
1. Вы говорите рекурсивно, но похоже, что ваш пример просматривается только до определенной глубины. Например: from
a
, tob
, tod
, мы получаем tof: [11, 14]
. Так почему этого нет вf
спискеa
?2. извините, обновлю пример
3. Что происходит, когда в конечных массивах есть повторяющиеся значения? Не могли бы вы описать это также в своем примере?
4. на самом деле конечный массив всегда уникален, уже обновите пример, спасибо 🙂
5. Примеры, в которых для имен свойств используются одиночные буквы, значительно затрудняют обсуждение проблемы («C, являющийся свойством a, или c, являющийся свойством b»). Гораздо лучше использовать уникальные слова.
Ответ №1:
Сначала я бы создал структуру, которая хранит противоположные отношения, то есть от дочернего элемента к родительскому.
Затем для каждой пары ключ / массив следуйте по пути (через новую структуру) вверх к его предкам и для каждого из них добавьте массив к одному и тому же ключу. Для этого я выбрал обход с использованием явной переменной стека, но он будет работать так же хорошо с рекурсивным обходом 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 resu<
}
// 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.log(result);
Ответ №2:
Вы можете использовать рекурсивный подход для каждого вложенного ключа ( addKeys
функции), используя Object.entries()
with 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.log(result)
Ответ №3:
Вы могли бы использовать вложенный подход с рекурсивной функцией с маркером выхода.
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.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }