4

I have a structure like this

[
    {"id": "as2is0", "replies": [{"id": "e345k2e", "replies": [. . .]} ]},
    {"id": "2ishkl8"}
] . . .

where it is hard to predict how many replies a comment has. I basically want to loop through every single comment, be it a reply or top-level comment. How do I do this? There can be replies to other replies as well, so my basic loop solution doesn't work.

ICanKindOfCode
  • 1,000
  • 1
  • 11
  • 32
  • I assume you already have recursive solution... Converting to "basic loop" covered in https://stackoverflow.com/questions/159590/way-to-go-from-recursion-to-iteration – Alexei Levenkov Dec 09 '18 at 07:47
  • I think this is not valid array syntax to start with... It looks more like an object to me. An array should contain items, not key& value pairs. – Ruby Racer Dec 09 '18 at 07:49
  • As @RubyRacer mentioned, the syntax is not correct. Please post a sample of actual data with valid format. – Jeto Dec 09 '18 at 07:50
  • @Jeto sorry, I have now posted what it looks like. – ICanKindOfCode Dec 09 '18 at 07:54
  • I have posted my answer below taking into consideration that the level of the comment and replies matter. Maybe you want to do something different for deep comments/replies – Ahmad Dec 09 '18 at 08:32

4 Answers4

3

What you want is a recursive function, which means it calls itself under certain conditions. Here's an example

const data = [
    {
      id: "abc",
      replies: [
        {id: "def", replies: [
          {id: 'ghi', replies: [] }
        ]} 
      ]
    },
    {
      id: "jkl",
      replies: [
        {id: "mno", replies: [
          {id: 'pqr', replies: [] }
        ]} 
      ]
    }
]

function logReplies(data) {
  data.forEach(item => {
    console.log('id:', item.id);
    if (item.replies) {
      logReplies(item.replies);
    }
  });
}

logReplies(data);

Documentation

https://developer.mozilla.org/en-US/docs/Glossary/Recursion

AnonymousSB
  • 3,516
  • 10
  • 28
1

Here is a very simple recursive function to just print the ids to get you started:

const data = [{
    id: "as2is0",
    replies: [{
      id: "e345k2e",
      replies: [{
        id: "e34112e",
        replies: []
      }]
    }]
  },
  {
    "id": "2ishkl8"
  }
]

// notice the function accepts an array as a parameter
const getComments = arr => arr.forEach(x => {   // <-- for every element
  if(x.id)
    console.log(x.id)
  if(x.replies)    // <-- if there are any children
    getComments(x.replies)  // <-- call with the children array as parameter now
})

getComments(data)  // <-- do the initial call of the function

The idea is to traverse the tree via calling getComments on every level and keep doing so until there is no longer any children/replies.

Akrion
  • 18,117
  • 1
  • 34
  • 54
0

If you're interested in retrieving flattened comments first, as opposed to doing your stuff directly while looping over it (what other answers point you to), you can do the following:

const comments = [
  {"id": "as2is0", "replies": [{"id": "e345k2e", "replies": []} ]},
  {"id": "2ishkl8"}
];
  
function getFlattenedComments(comments) {
  const flattenedComments = [];
  for ({replies, ...commentWithoutReplies} of comments) {
    flattenedComments.push(commentWithoutReplies);
    if (replies) {
      flattenedComments.push(...getFlattenedComments(replies));
    }
  }
  return flattenedComments;
}

console.log(getFlattenedComments(comments));

This will also ensure any property that isn't replies (not just id, potentially others too if you have them) will remain in the flattened collection.

Jeto
  • 14,596
  • 2
  • 32
  • 46
0

You will need to use recursion to resolve your problem. I am not sure what you want to do with each reply, or what action is needed on each sub-comment, but in my snippet below, I assumed that you want to parse them in a tree-like structure, with indentations to mark their level in the tree.

Of course, you can change the parsing code and replace it with whatever action is needed in your case.

// here is my attempt at building a complex layers of nested comments
var comments = [
    {"id": "as2is0", "replies": [
                     {"id": "e345k2e", "replies": []},
                     {"id": "f12ba55", "replies": [{"id":"st123abc","replies":[{"id": "y345k2e", "replies": []}]}]} ]},
    {"id": "k345k2e", "replies": [{"id": "q96yyt", "replies": []}]},
    {"id": "2ishkl8"}
];

// begin at the outer level, parse each element separately
comments.forEach(function(c){
  console.log(parse(c));
});


// the parse function takes two parameters: the comment object and the level
function parse(c,lvl) {
   //if level is not specified, it is assumed to be root level
   if(!lvl) { lvl = 0 }
   
   // if current comment contains no replies, or empty array:
   if(!c.replies || c.replies.length==0) {
      return  c.id;   
   } else {
      // build a string to contain all nested replies
      var str = c.id + " : " ;
      // iterate through all replies of current comment
      c.replies.forEach(function(r){
        
        str +=  "\n" ;                // add a new line
        str += ("  ").repeat( lvl+1); // indent reply as depending on the level
        str += parse(r,(lvl+1));      // recursive call to parse cunction
                                      // but with one level deeper
      });
      return str;
   }
   
}
Ahmad
  • 12,336
  • 6
  • 48
  • 88