0

I'm working on flatten array function. It takes an input like this

const input = [
  {
    "value": "value0",
    "children": []
  },
  {
    "value": "value1",
    "children": [
      {
        "value": "value2",
        "children": [
          {
            "value": "value3",
            "children": []
          }
        ]
      },
      {
        "value": "value4",
        "children": []
      }
    ]
  },
  {
    "value": "value5",
    "children": []
  },
  {
    "value": "value6",
    "children": []
  }
];

and return an array

[
  {"value":"value0"},
  {"value":"value1"},
  {"value":"value2"},
  {"value":"value3"},
  {"value":"value4"},
  {"value":"value5"},
  {"value":"value6"}
]

I have solved this problem. Here is my former wrong code and I was trying to debug it

function flatArray(input) {
  if(input.length === 0) return [];
  let res = [];
  input.forEach(i => {
    for(let key of Object.keys(i)) {
      if(key === 'value') {
        res.push({[key]: i[key]});
      } else {
        const arr = flatArray(i[key]);
        res.concat(arr);
        console.log(res);
      }
    }
  });
  return res;
}

PS: It's wrong because the misuse of concat

The output is weird. I got

enter image description here

I'm wondering why the first three are type of object? And why, like the first output, can get an array with 4 elements instead of getting an array with only {value: value0}?

I guess it has something to do with closures but I can't explain this thing. Can anyone help me?

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • In the `else` statement shoudn't you be passing `i.children` instead of `i[key]`? – Thiago Loddi Aug 27 '19 at 02:10
  • @ThiagoLoddi When `key` isn't `value`, it's `children`, so `i[key]` is the same as `i.children`. – Barmar Aug 27 '19 at 02:13
  • `if(input.length === 0) return [];` is a waste. If *input* has length 0 then *forEach* won't do anything and the function will return the empty *res* array. – RobG Aug 27 '19 at 02:19
  • 1
    The console holds live connections to objects and arrays. If the array is modified, you'll see the final version when you expand it. Use `console.log(JSON.stringify(res))` to get snapshots. – Barmar Aug 27 '19 at 02:21
  • @Barmar Cool man, you are the only man who get the point! You save my morning. Thank you very much! – Miller Dong Aug 27 '19 at 15:08

2 Answers2

0

Well, it looks like you answered yourself:

PS: It's wrong because the misuse of concat

The concat method won't change the existing arrays, but return a new one. So you have to assign its output to you res variable:

function flatArray(input) {
  if(input.length === 0) return [];

  let res = [];

  input.forEach(i => {
    for(let key of Object.keys(i)) {
      if(key === 'value') {
        res.push({[key]: i[key]});
      } 
      else {
        const arr = flatArray(i[key]);
        res =  res.concat(arr);
      }
    }
  });
  return res;
}
Thiago Loddi
  • 2,212
  • 4
  • 21
  • 35
  • He said he already fixed the function. His question is why he was getting unexpected output from `console.log(res);` – Barmar Aug 27 '19 at 02:22
0

If the order of objects in the output doesn't matter, I would structure this differently. Put the top array elements into input and traverse each object in input: for each object, remove the array valued-keys and concat them to input and push the non-array-valued object to res. Continue iteration until input is empty. You could output the same ordering by inserting each child list to the head of input for depth-first traversal. Sorry I didn't actually answer how to fix the recursive one.

karmakaze
  • 34,689
  • 1
  • 30
  • 32