Javascript Transform рекурсивно объект, который ссылается на другой атрибут, используя lodash или другую библиотеку

Я хочу преобразовать объект 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 или другую библиотеку.

Вы говорите рекурсивно, но похоже, что ваш пример выглядит только до определенной глубины. Например: из a в b, в d мы получаем f: [11, 14]. Так почему же этого нет в f списке a?

trincot 09.04.2019 19:45

извините обновлю пример

David Async 09.04.2019 20:01

Что происходит, когда в окончательных массивах есть повторяющиеся значения? Не могли бы вы осветить это также в своем примере?

trincot 09.04.2019 20:02

на самом деле конечный массив всегда уникален, уже обновил пример, спасибо :)

David Async 09.04.2019 20:09

Примеры, в которых для названий свойств используются одиночные буквы, значительно усложняют обсуждение проблемы («С — это свойство а, или с — свойство b»). Гораздо лучше использовать уникальные слова.

Heretic Monkey 09.04.2019 20:14

@HereticMonkey обновлен :)

David Async 09.04.2019 20:29
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
6
59
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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.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);

Другие вопросы по теме