Tania12
Tania12

Reputation: 373

Javascript rename property in 3D array

I have a multidimentionnal array and i want to rename property recursevly, i've tried this function

const newMenu =
        Array.isArray(copyMenu) &&
        copyMenu.length > 0 &&
        copyMenu.map(({ families: children, id: key, label: title, ...rest }) => ({
            key,
            title,
            ...rest,
            children,
        }));

But it rename just the big array, not the properties inside table property This is my input array :

const input = [
{
    id: 9040,
    label: "33",
    tables: [
      {
        id: 8957,
        label: "THB_Adresse_Famille",
        idFather: 8957,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 8941,
        label: "THB_Contact_Famille",
        idFather: 8941,
        tableIsFamily: false,
        tables: [
          { id: 8947, label: "THB_Contact_Table", idFather: 8941 },
          { id: 9855, label: "THB_Contact_Table_BIS", idFather: 8941 }
        ]
      },
      {
        id: 8949,
        label: "THB_Societe_Famille",
        idFather: 8949,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 8983,
        label: "THB_TELEPHONE",
        idFather: 8983,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 10070,
        label: "THB_TEST_5708",
        idFather: 10070,
        tableIsFamily: false,
        tables: []
      }
    ]
  },
   {
    id: 9761,
    label: "1111111",
    tables: [
      {
        id: 9742,
        label: "RRA PROTOCOLE",
        idFather: 9742,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 9753,
        label: "RRA TEST CASE LINE",
        idFather: 9753,
        tableIsFamily: false,
        tables: []
      }
    ]
  },
]

The output should be ike this :

const output = [
{
    key: 9040,
    title: "33",
    children: [
      {
        key: 8957,
        title: "THB_Adresse_Famille",
        idFather: 8957,
        tableIsFamily: false,
        children: []
      },
      {
        key: 8941,
        title: "THB_Contact_Famille",
        idFather: 8941,
        tableIsFamily: false,
        children: [
          { key: 8947, title: "THB_Contact_Table", idFather: 8941 },
          { key: 9855, title: "THB_Contact_Table_BIS", idFather: 8941 }
        ]
      },
      {
        key: 8949,
        title: "THB_Societe_Famille",
        idFather: 8949,
        tableIsFamily: false,
        children: []
      },
      {
        key: 8983,
        title: "THB_TELEPHONE",
        idFather: 8983,
        tableIsFamily: false,
        children: []
      },
      {
        key: 10070,
        title: "THB_TEST_5708",
        idFather: 10070,
        tableIsFamily: false,
        children: []
      }
    ]
  },
 {
    key: 9761,
    title: "1111111",
    children: [
      {
        key: 9742,
        title: "RRA PROTOCOLE",
        idFather: 9742,
        tableIsFamily: false,
        children: []
      },
      {
        key: 9753,
        title: "RRA TEST CASE LINE",
        idFather: 9753,
        tableIsFamily: false,
        children: []
      }
    ]
  },
]

I'v searched on stackoverflow but i don't found any solutions to this case, any help will be appreciated. Thank you

Upvotes: 0

Views: 62

Answers (4)

jsN00b
jsN00b

Reputation: 3691

Looks like a number of good answers have been provided. Here's one potential implementation to achieve the desired objective:

Sample Code

const replacePropsMap = {
  id: 'key',
  label: 'title',
  tables: 'children'
};

const renameProps = (arr = inputArr, propsMap = replacePropsMap) => (
  arr.reduce((fin, itm) => ([
    ...fin,
    {
      ...(
      Object.entries(itm).reduce((fin2, itm2) => ({
        ...fin2,
        ...(
          itm2[0] in propsMap
            ? { [propsMap[itm2[0]]]: itm2[1] }
            : {}
        )
      }), {})
      ),
      children: itm && itm.tables && itm.tables.length > 0
        ? renameProps(itm.tables)
        : []
    }
  ]), [])
);

Explanation

  • Use .reduce to iterate through the array (with the aggregator as fin and each item as itm)
  • Use ... spread-operator to first place existing items (from past iterations)
  • Next, for current itm, use Object.entries() and .reduce to filter-out id, label, tables props, but retain all other props
  • Use key, title to hold values of id, label respectively
  • Recurse the above for the tables array (if it exists) and store the result in children prop.

Code Snippet

const inputArr = [{
    id: 9040,
    label: "33",
    tables: [
      {
        id: 8957,
        label: "THB_Adresse_Famille",
        idFather: 8957,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 8941,
        label: "THB_Contact_Famille",
        idFather: 8941,
        tableIsFamily: false,
        tables: [
          { id: 8947, label: "THB_Contact_Table", idFather: 8941 },
          { id: 9855, label: "THB_Contact_Table_BIS", idFather: 8941 }
        ]
      },
      {
        id: 8949,
        label: "THB_Societe_Famille",
        idFather: 8949,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 8983,
        label: "THB_TELEPHONE",
        idFather: 8983,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 10070,
        label: "THB_TEST_5708",
        idFather: 10070,
        tableIsFamily: false,
        tables: []
      }
    ]
  }, {
    id: 9761,
    label: "1111111",
    tables: [
      {
        id: 9742,
        label: "RRA PROTOCOLE",
        idFather: 9742,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 9753,
        label: "RRA TEST CASE LINE",
        idFather: 9753,
        tableIsFamily: false,
        tables: []
      }
    ]
  }
];

const replacePropsMap = {
  id: 'key',
  label: 'title',
  tables: 'children'
};

const renameProps = (arr = inputArr) => (
    arr.reduce((fin, itm) => ([
    ...fin,
    {
        ...(
        Object.entries(itm).reduce((fin2, itm2) => ({
            ...fin2,
          ...(
            itm2[0] in replacePropsMap
                ? { [replacePropsMap[itm2[0]]]: itm2[1] }
              : {}
          )
        }), {})
      ),
      children: itm && itm.tables && itm.tables.length > 0
        ? renameProps(itm.tables)
        : []
    }
  ]), [])
);

console.log(renameProps());

Upvotes: 0

Maurits
Maurits

Reputation: 21

I see your attempted solution is lacking the recursive call you say you want to implement. It may be a little tricky to conceive. You essentially need to wrap the repeating code in a function.

const recurse = (input) =>
  input?.map(({ tables, id, label, ...rest }) =>
    ({ children: recurse(tables), key: id, title: label, ...rest }))

Then, notice the function calls itself on the relevant part, a.k.a. the general case. Also not unimportantly, the function needs to know when to stop, i.e. when it has hit the base case. Without checking for the base case you will quickly find out where this website gets its name from. In the example above I did apply optional chaining so it is a bit subtle.

Edit: with regard to destructuring, there are roughly two equivalent approaches (as far as I can see), here is the other which matches more with your initial approach:

const recurse = (input) =>
  input?.map(({ tables, id: key, label: title, ...rest }) =>
    ({ children: recurse(tables), key, title, ...rest }))

Upvotes: 1

secan
secan

Reputation: 2679

A potential solution could be:

const input = [{
    id: 9040,
    label: "33",
    tables: [{
        id: 8957,
        label: "THB_Adresse_Famille",
        idFather: 8957,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 8941,
        label: "THB_Contact_Famille",
        idFather: 8941,
        tableIsFamily: false,
        tables: [{
            id: 8947,
            label: "THB_Contact_Table",
            idFather: 8941
          },
          {
            id: 9855,
            label: "THB_Contact_Table_BIS",
            idFather: 8941
          }
        ]
      },
      {
        id: 8949,
        label: "THB_Societe_Famille",
        idFather: 8949,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 8983,
        label: "THB_TELEPHONE",
        idFather: 8983,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 10070,
        label: "THB_TEST_5708",
        idFather: 10070,
        tableIsFamily: false,
        tables: []
      }
    ]
  },
  {
    id: 9761,
    label: "1111111",
    tables: [{
        id: 9742,
        label: "RRA PROTOCOLE",
        idFather: 9742,
        tableIsFamily: false,
        tables: []
      },
      {
        id: 9753,
        label: "RRA TEST CASE LINE",
        idFather: 9753,
        tableIsFamily: false,
        tables: []
      }
    ]
  },
];

function updateKeys(arr) {
  return arr.map(({
    tables,
    id: key,
    label: title,
    ...rest
  }) => {
    const children = Array.isArray(tables) && tables.length > 0 ? updateKeys(tables) : tables;
    return {
      key,
      title,
      children,
      ...rest
    }
  });
}

const output = updateKeys(input);

console.log(output);

Upvotes: -1

Hassan Imam
Hassan Imam

Reputation: 22564

You can use recursive approach to rename your keys by maintaining a lookup for renamed keys and recursively calling your function for array values.

const input = [ { id: 9040, label: "33", tables: [ { id: 8957, label: "THB_Adresse_Famille", idFather: 8957, tableIsFamily: false, tables: [] }, { id: 8941, label: "THB_Contact_Famille", idFather: 8941, tableIsFamily: false, tables: [ { id: 8947, label:"THB_Contact_Table", idFather: 8941 }, { id: 9855, label: "THB_Contact_Table_BIS", idFather: 8941 } ] }, { id: 8949, label: "THB_Societe_Famille", idFather: 8949, tableIsFamily: false, tables: [] }, { id: 8983, label: "THB_TELEPHONE", idFather: 8983, tableIsFamily: false, tables: [] }, { id: 10070, label: "THB_TEST_5708", idFather: 10070, tableIsFamily: false, tables: [] } ] }, { id: 9761, label: "1111111", tables: [ { id: 9742, label: "RRA PROTOCOLE", idFather: 9742, tableIsFamily: false, tables: [] }, { id: 9753, label: "RRA TEST CASE LINE", idFather: 9753, tableIsFamily: false, tables: [] } ] }, ],
    keys = { id: 'key', label: 'title', tables: 'children'},
    rename = (arr) => {
      return arr.map(o => {
        return Object.fromEntries(Object.keys(o).map(k => {
          const key = keys[k] || k;
          const value = Array.isArray(o[k]) ? rename(o[k]) : o[k];
          return [key, value];
        }));
      });
    };
console.log(rename(input));

Upvotes: 2

Related Questions