Преобразование объекта рекурсивно - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть объект или массив объектов с реквизитами, содержащими строки, массивы и другие объекты.

Я хочу преобразовать вложенные массивы, содержащие объекты с языком поддержки, в объект с языком в качестве ключа и самим объектом в качестве свойства.

Допустим, я хочу рекурсивно преобразовать этот объект:

{
    "WhatPage": [
        {
            "id": 1,
            "WhatPageTranslations": [
                {
                    "id": 1,
                    "title": "What",
                    "WhatPageId": 1,
                    "language": "en"
                },
                {
                    "id": 2,
                    "title": "Qué",
                    "WhatPageId": 1,
                    "language": "es"
                },
            ],
            "WhatPageImages": [
                {
                    "id": 1,
                    "title": "image title 1",
                    "WhatPageId": 1,
                    "WhatPageImagesTranslations": [
                        {
                            "id": 1,
                            "title": "What",
                            "WhatPageImageId": 1,
                            "language": "en"
                        },
                        {
                            "id": 2,
                            "title": "Qué",
                            "WhatPageImageId": 1,
                            "language": "es"
                        },
                    ]
                },
            ]
        }
    ]
}

Затем я могу использовать эту функцию, которая проверяет, является ли она массивом или объектом, и рекурсивно преобразовывает данные:

export const transformTranslatedData = function(data) {
    var clonedData = JSON.parse(JSON.stringify(data));
    const transform = function(data) {
        for (var prop in data) {
            if (data[prop].length > 0 && data[prop] instanceof Array && data[prop][0].hasOwnProperty('language')) {
                var transformedData = data[prop].reduce(function(prev, current, index) {
                    prev[current.language] = current;

                    return prev;
                }, {});
                data[prop] = transformedData;

            } else if (data[prop] instanceof Object && !(data[prop] instanceof Array)) {
                transformTranslatedData(data[prop]);
            } else if (data[prop] instanceof Array) {
                let array = JSON.parse(JSON.stringify(data[prop]));
                array.forEach((item) => {
                    transformTranslatedData(item);
                });
            }
        }

        return data;
    };
    if (clonedData instanceof Array) {
        var newData = [];
        clonedData.map((item) => {
            newData.push(transform(item));
        });
    } else if (clonedData instanceof Object && !(clonedData instanceof Array)) {
        var newData = {};

        newData = transform(clonedData);
    }

    return newData;
};

Это работает, но только для первого уровня объекта - WhatPageTranslations -. На втором уровне, когда он достигает WhatPageImagesTranslations, он преобразует данные, но эти данные не добавляются к объекту.

Если кто-нибудь знает, почему это происходит, я был бы благодарен!

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Я думаю, вы можете упростить вашу рекурсивную функцию. В вашем решении вы, кажется, много клонируете (при каждом рекурсивном вызове). Вы можете создать глубокую копию один раз, а затем свободно изменять ее в своей рекурсивной функции (как упоминалось в @Barmar).

Это значительно сосредотачивает наши усилия на изучении и принятии решения о том, следует ли преобразовывать «текущую» часть данных в рекурсии:

const myData = {
  "WhatPage": [{
    "id": 1,
    "WhatPageTranslations": [{
        "id": 1,
        "title": "What",
        "WhatPageId": 1,
        "language": "en"
      },
      {
        "id": 2,
        "title": "Qué",
        "WhatPageId": 1,
        "language": "es"
      },
    ],
    "WhatPageImages": [{
      "id": 1,
      "title": "image title 1",
      "WhatPageId": 1,
      "WhatPageImagesTranslations": [{
          "id": 1,
          "title": "What",
          "WhatPageImageId": 1,
          "language": "en"
        },
        {
          "id": 2,
          "title": "Qué",
          "WhatPageImageId": 1,
          "language": "es"
        },
      ]
    }, ]
  }]
};


function transform(data) {
  // base case
  if (data instanceof Array && data.length && data[0].hasOwnProperty('language')) {
    return data.reduce((acc, curr) => {
      acc[curr.language] = curr;
      return acc;
    }, {});
  }

  // array but not base case
  if (data instanceof Array) return data.map(transform);

  // object but not base case
  if (typeof data === 'object' && !(data instanceof Array)) {
    for (let key in data) {
      data[key] = transform(data[key]);
    }
  }

  // primitive, so return as is
  return data;
}

console.log(transform(JSON.parse(JSON.stringify(myData))));
0 голосов
/ 01 ноября 2018

Когда вы вызываете transformTranslatedData рекурсивно, он создает копию объекта, который вы передаете, и изменяет его. Таким образом, объект, через который вы возвращаетесь, не изменяется.

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

        } else if (data[prop] instanceof Object && !(data[prop] instanceof Array)) {
            data[prop] = transformTranslatedData(data[prop]);
        } else if (data[prop] instanceof Array) {
            let array = JSON.parse(JSON.stringify(data[prop]));
            data[prop] = array.map((item) => {
                transformTranslatedData(item);
            });
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...