Как заменить ключ во вложенном объекте - PullRequest
3 голосов
/ 24 октября 2019

У меня есть такой объект,

{
  id: '1',
  displaName: 'A',
  children: [
  {
    id: '2',
    displayName: 'B',
    children: [
    {
      id: '3',
      displayName: 'C',
      children: [
            //More nested array here
      ]
    }
    ]
  }]
}

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

{
  id: '1',
  label: 'A',  //change key displayName => label
  children: [
  {
    id: '2',
    label: 'B',  //change key displayName => label
    children: [
    {
      id: '3',
      label: 'C',  //change key displayName => label
      children: [
            //More nested array here
      ]
    }
    ]
  }]
}

Я пробовал это, но не смог заменить ключ во вложенном массиве,

const newKeys = { displaName: "label"};
const renamedObj = renameKeys(resp.data, newKeys);
console.log(renamedObj);

function renameKeys(obj, newKeys) {
  const keyValues = Object.keys(obj).map(key => {
    console.log(key);
    let newKey = null
    if(key === 'displayName'){
       newKey = 'label'
    }else{
       newKey = key
    }
    console.log(newKey);
    return { [newKey]: obj[key] };
  });
  return Object.assign({}, ...keyValues);
}

Пожалуйста, помогите мне разобраться в этом.

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 24 октября 2019
  1. В вашем коде есть опечатка. Некоторые переменные отображаются как displaName вместо displayName.

  2. Вам нужно рекурсивно вызывать функцию, чтобы работать так, как вы планировали.

  3. Вы не использовали newKeys переменную для переименования. Вы просто жестко закодировали это как newKey = 'label'. Но этот вопрос не имеет отношения к проблеме.

const resp = {
  data: {
    id: '1',
    displayName: 'A',
    children: [{
      id: '2',
      displayName: 'B',
      children: [{
        id: '3',
        displayName: 'C',
        children: [
          //More nested array here
        ]
      }]
    }]
  }
}

const newKeys = {
  displayName: "label"
};
const renamedObj = this.renameKeys(resp.data, newKeys);
console.log(renamedObj);

function renameKeys(obj, newKeys) {
  const keyValues = Object.keys(obj).map(key => {
    let newKey = null
    if (key === 'displayName') {
      newKey = newKeys.displayName
    } else {
      newKey = key
    }
    if (key === 'children') {
      obj[key] = obj[key].map(obj => renameKeys(obj, newKeys));    
    }
    return {
      [newKey]: obj[key]
    };
  });
  return Object.assign({}, ...keyValues);
}
0 голосов
/ 24 октября 2019

Существующие ответы великолепны, но я не могу удержаться от добавления JSON.stringify версии:

const data = { id: '1', displayName: 'A', children: [ { id: '2', displayName: 'B', children: [ { id: '3', displayName: 'C', children: [] }] }] };
const result = JSON.parse(JSON.stringify(data).replace(/"displayName":/g, '"value":'));
console.log(result);

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

Если у вас есть несколько замен, вы можете использовать

const data = { id: '1', displayName: 'A', children: [ { id: '2', displayName: 'B', children: [ { id: '3', displayName: 'C', children: [] }] }] };
const swaps = {displayName: "foo", children: "baz", id: "corge"};
const pattern = new RegExp(
  Object.keys(swaps).map(e => `(?:"(${e})":)`).join("|"), "g"
);
const result = JSON.parse(
  JSON.stringify(data).replace(pattern, m => `"${swaps[m.slice(1,-2)]}":`)
);
console.log(result);

Более традиционным рекурсивным вариантом может быть следующий (все еще предполагается / жесткие коды children):

const changeKey = (node, keySubs) => 
  Object.entries(keySubs).reduce((a, [oldKey, newKey]) => {
    a[newKey] = a[oldKey];
    delete a[oldKey];
    return a;
  }, {...node, children: node.children.map(e => changeKey(e, keySubs))})
;

const data = { id: '1', displayName: 'A', children: [ { id: '2', displayName: 'B', children: [ { id: '3', displayName: 'C', children: [] }] }] };
const swaps = {displayName: "label", id: "better id"};
console.log(changeKey(data, swaps));

Итеративный:

const changeKey = (node, keySubs) => {
  const result = {children: []};
  const stack = [[node, result]];

  while (stack.length) {
    const [curr, parent] = stack.pop();
    const child = Object.entries(keySubs)
      .reduce((a, [oldKey, newKey]) => {
        a[newKey] = a[oldKey];
        delete a[oldKey];
        return a;
      }, {...curr, children: []})
    ;
    parent.children.push(child);
    stack.push(...curr.children.map(e => [e, child]));
  }

  return result;
};

const data = { id: '1', displayName: 'A', children: [ { id: '2', displayName: 'B', children: [ { id: '3', displayName: 'C', children: [] }] }] };
const swaps = {displayName: "label", id: "better id"};
console.log(changeKey(data, swaps));
0 голосов
/ 24 октября 2019

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

const orig = {
  id: '1',
  displayName: 'A',
  children: [{
    id: '2',
    displayName: 'B',
    children: [{
      id: '3',
      displayName: 'C',
      children: [
        //More nested array here
      ]
    }]
  }]
};

const updateDisplayNameToLabel = (val, keysMap) => {
  if (val == null) return null;
  if (Array.isArray(val)) {
    return val.map(item => updateDisplayNameToLabel(item, keysMap));
  } else if (typeof val == "object") {
    return Object.keys(val).reduce((obj, key) => {
      const propKey = updateDisplayNameToLabel(key, keysMap);
      const propVal = updateDisplayNameToLabel(val[key], keysMap);
      obj[propKey] = propVal;
      return obj;
    }, {});
  } else if (typeof val === "string") {
    return keysMap[val] || val;
  }
  return val;
}

const keysToUpdate = {
  displayName: 'label',
  children: 'items'
};

const updated = updateDisplayNameToLabel(orig, keysToUpdate);

console.log(updated);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...