Javascript Transform рекурсивный объект, который ссылается на другой атрибут, используя lodash или другой lib - PullRequest
0 голосов
/ 09 апреля 2019

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

Ответы [ 3 ]

1 голос
/ 09 апреля 2019

Сначала я бы создал структуру, которая хранит противоположные отношения, то есть от дочернего элемента к родительскому.

Затем для каждой пары ключ / массив следуйте по пути (через новую структуру) вверх к его предкам и для каждого из них добавьте массив к тому же ключу. Для этого я выбрал обход, используя явную переменную стека, но он бы также работал с рекурсивным обходом 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.log(result);
1 голос
/ 09 апреля 2019

Вы можете использовать вложенный подход с рекурсивной функцией с маркером выхода.

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; }
0 голосов
/ 09 апреля 2019

Вы можете использовать рекурсивный подход для каждой вложенной клавиши (функция 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.log(result)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...