Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive Map function

I'm having hard time figuring out how to do this recursive map function. I have an array that look like this.

var array = [
      {
        id: 1,
        label: 'Satisfied customers',
        children: [
          {
            id: 2,
            label: 'Good food',
            icon: 'restaurant_menu',
            children: [

              { id: 3, label: 'Quality ingredients'},
              { id: 4, label: 'Good recipe' }
            ]
          },
          {
            id: 5,
            label: 'Good service',
            icon: 'room_service',
            children: [
              { id: 6, label: 'Prompt attention' },
              { id: 7, label: 'Professional waiter' }
            ]
          },
          {
            id: 8,
            label: 'Pleasant surroundings',
            icon: 'photo',
            children: [
              {
                id: 9,
                label: 'Happy atmosphere (not tickable)',
                tickable: false,
              },
              {
                id: 10,
                label: 'Good table presentation (disabled node)',
                disabled: true,
              },
              {
                id: 11,
                label: 'Pleasing decor',
              }
            ]
          },
          {
            id: 12,
            label: 'Extra information (has no tick)',
            noTick: true,
            icon: 'photo'
          },
          {
            id: 13,
            label: 'Forced tick strategy (to "strict" in this case)',
            tickStrategy: 'strict',
            icon: 'school',
            children: [
              {
                id: 14,
                label: 'Happy atmosphere',
              },
              {
                id: 15,
                label: 'Good table presentation',
              },
              {
                id: 16,
                label: 'Very pleasing decor',
              }
            ]
          }
        ]
      }
    ];

This is the array looks like... enter image description here

As you can see the children is recursive.

I need to put them into one array. My code doesn't work an has an error.

const result = [];   
const map = (e) => {

    result.push({
        id: e.id,
        label: e.label,
    })

    e.children.map(map)


};

array.map(map);

the error is on e.children.map(map). enter image description here

I need to push them all in array variable but I don't know how to do this. TY

like image 369
Rbex Avatar asked Dec 04 '22 18:12

Rbex


2 Answers

You need to check if current item has children element, and you can use forEach instead because map return new array and forEach just go throw each element.

const cb = (e) => {
    res.push({
        id: e.id,
        label: e.label,
    });
    e.children && e.children.forEach(cb);
}
array.forEach(cb);
like image 89
Dmitry Dubovetsky Avatar answered Dec 06 '22 08:12

Dmitry Dubovetsky


A great way to learn about mutual recursion using vanilla JavaScript -

const transform1 = ({ id = 0, label = "", children = [] }) =>
  [ { id, label }, ...transformAll (children) ] // calls transformAll

const transformAll = (children = []) =>
  children .flatMap (c => transform1 (c)) // calls transform1

console.log(transformAll(array))

Output -

[
  {
    "id": 1,
    "label": "Satisfied customers"
  },
  {
    "id": 2,
    "label": "Good food"
  },
  {
    "id": 3,
    "label": "Quality ingredients"
  },
  {
    "id": 4,
    "label": "Good recipe"
  },
  {
    "id": 5,
    "label": "Good service"
  },
  {
    "id": 6,
    "label": "Prompt attention"
  },
  {
    "id": 7,
    "label": "Professional waiter"
  },
  {
    "id": 8,
    "label": "Pleasant surroundings"
  },
  {
    "id": 9,
    "label": "Happy atmosphere (not tickable)"
  },
  {
    "id": 10,
    "label": "Good table presentation (disabled node)"
  },
  {
    "id": 11,
    "label": "Pleasing decor"
  },
  {
    "id": 12,
    "label": "Extra information (has no tick)"
  },
  {
    "id": 13,
    "label": "Forced tick strategy (to \"strict\" in this case)"
  },
  {
    "id": 14,
    "label": "Happy atmosphere"
  },
  {
    "id": 15,
    "label": "Good table presentation"
  },
  {
    "id": 16,
    "label": "Very pleasing decor"
  }
]

Expand the snippet below the verify the results in your own browser -

var array = [
      {
        id: 1,
        label: 'Satisfied customers',
        children: [
          {
            id: 2,
            label: 'Good food',
            icon: 'restaurant_menu',
            children: [

              { id: 3, label: 'Quality ingredients'},
              { id: 4, label: 'Good recipe' }
            ]
          },
          {
            id: 5,
            label: 'Good service',
            icon: 'room_service',
            children: [
              { id: 6, label: 'Prompt attention' },
              { id: 7, label: 'Professional waiter' }
            ]
          },
          {
            id: 8,
            label: 'Pleasant surroundings',
            icon: 'photo',
            children: [
              {
                id: 9,
                label: 'Happy atmosphere (not tickable)',
                tickable: false,
              },
              {
                id: 10,
                label: 'Good table presentation (disabled node)',
                disabled: true,
              },
              {
                id: 11,
                label: 'Pleasing decor',
              }
            ]
          },
          {
            id: 12,
            label: 'Extra information (has no tick)',
            noTick: true,
            icon: 'photo'
          },
          {
            id: 13,
            label: 'Forced tick strategy (to "strict" in this case)',
            tickStrategy: 'strict',
            icon: 'school',
            children: [
              {
                id: 14,
                label: 'Happy atmosphere',
              },
              {
                id: 15,
                label: 'Good table presentation',
              },
              {
                id: 16,
                label: 'Very pleasing decor',
              }
            ]
          }
        ]
      }
    ];
    
const transform1 = ({ id = 0, label = "", children = [] }) =>
  [ { id, label }, ... transformAll (children) ]
  
const transformAll = (children = []) =>
  children .flatMap (c => transform1 (c))
  
console.log(transformAll(array))

A tour of Flat Earth

If you've never seen .flatMap before -

xs.flatMap(f) == xs.map(f).reduce((a,b) => a.concat(b), [])
xs.flatMap(f) == xs.reduce((a,b) => a.concat(f(b)), [])

It's best seen with a simple demo -

const twice = x =>
  [ x, x ]
  
console .log
  ( [ 'a', 'b', 'c' ] .flatMap (twice) // [ 'a', 'a', 'b', 'b', 'c', 'c' ]
  , [ 1, 2, 3, 4, 5 ] .flatMap (twice) // [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]
  )

flatMap is useful for all kinds of things -

const tree =
  [ 0, [ 1 ], [ 2, [ 3 ], [ 4, [ 5 ] ] ] ]
  
const all = ([ value, ...children ]) =>
  [ value, ...children .flatMap (all) ]
  
console .log (all (tree))
// [ 0, 1, 2, 3, 4, 5 ]

really cool things -

const ranks =
  [ 'J', 'Q', 'K', 'A' ]
  
const suits =
  [ '♡', '♢', '♤', '♧' ]

const cards =
  ranks .flatMap (r =>
  suits .flatMap (s =>
  [ [ r, s ] ]
  ))

console .log (cards)
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
like image 20
Mulan Avatar answered Dec 06 '22 09:12

Mulan