I'm implementing an API for threaded comments like reddit! but I have a problem that I don't know how to solve, I will give you just the necessary context:
I have a list of dicts, where each dict represent the information of a comment extracted from the dabatabase, it looks like this:
comments:List[Dict] = [
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('b1865484-fdef-11eb-90ee-0242ac150003'),
'level': 0,
'parent_id': None,
'reference_id': UUID('e480ae80-89e2-4d38-ba92-570e863fec87')
},
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('b76db7ac-fdef-11eb-90ee-0242ac150003'),
'level': 1,
'parent_id': UUID('b1865484-fdef-11eb-90ee-0242ac150003'),
'reference_id': UUID('b621b10b-47c8-4492-881d-577e5a7a98af')
},
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('9a3cdb12-fe09-11eb-a65d-0242ac150003'),
'level': 1,
'parent_id': UUID('b1865484-fdef-11eb-90ee-0242ac150003'),
'reference_id': UUID('09280706-4ab6-459a-86cc-dc953479c356')
},
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('a53c7522-fe09-11eb-a65d-0242ac150003'),
'level': 2,
'parent_id': UUID('9a3cdb12-fe09-11eb-a65d-0242ac150003'),
'reference_id': UUID('124ece3a-a8ff-415b-8e98-66852d4d7e16')
},
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('a349cf9a-fe12-11eb-8cc0-0242ac150003'),
'level': 3,
'parent_id': UUID('a53c7522-fe09-11eb-a65d-0242ac150003'),
'reference_id': UUID('e6dbbf9c-ff0b-4337-a9c5-aa9eedfebc07')
}
]
and my objective is to convert that into a list of nested dicts, inserting the replies/sub-comments in a replies
key inside each dict, I want it to look like this:
comments:List[Dict] = [
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('b1865484-fdef-11eb-90ee-0242ac150003'),
'level': 0,
'parent_id': None,
'reference_id': UUID('e480ae80-89e2-4d38-ba92-570e863fec87'),
'replies': [
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('b76db7ac-fdef-11eb-90ee-0242ac150003'),
'level': 1,
'parent_id': UUID('b1865484-fdef-11eb-90ee-0242ac150003'),
'reference_id': UUID('b621b10b-47c8-4492-881d-577e5a7a98af')
},
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('9a3cdb12-fe09-11eb-a65d-0242ac150003'),
'level': 1,
'parent_id': UUID('b1865484-fdef-11eb-90ee-0242ac150003'),
'reference_id': UUID('09280706-4ab6-459a-86cc-dc953479c356'),
'replies': [
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('a53c7522-fe09-11eb-a65d-0242ac150003'),
'level': 2,
'parent_id': UUID('9a3cdb12-fe09-11eb-a65d-0242ac150003'),
'reference_id': UUID('124ece3a-a8ff-415b-8e98-66852d4d7e16'),
'replies': [
{
'body': 'holaaaaaaaaaaaaaaaaaaa',
'id': UUID('a349cf9a-fe12-11eb-8cc0-0242ac150003'),
'level': 3,
'parent_id': UUID('a53c7522-fe09-11eb-a65d-0242ac150003'),
'reference_id': UUID('e6dbbf9c-ff0b-4337-a9c5-aa9eedfebc07')
}
]
}
]
}
]
}
]
Where the children are nested inside their parents. I tried a recursive function:
def parse(comments:List[Dict]) -> List[Dict]:
output_nested = []
while len(comments) > 0:
comment = comments.pop(0)
replies = [reply for reply in comments if reply['parent_id'] == comment['id']]
replies = parse(replies)
comment['replies'] = replies
comments = [c for c in comments if c['parent_id'] != comment['id']]
output_nested.append(comment)
return output_nested
but it is not working as expected, and actually I run out of ideas on how to do this.
You can use recursion:
#an object to make your basic input compatible with the function below
class UUID:
def __init__(self, _id):
self.id = _id
def __eq__(self, uuid):
return self.id == getattr(uuid, 'id', None)
def __repr__(self):
return f'{self.__class__.__name__}("{self.id}")'
comments = [{'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("b1865484-fdef-11eb-90ee-0242ac150003"), 'level': 0, 'parent_id': None, 'reference_id': UUID("e480ae80-89e2-4d38-ba92-570e863fec87")}, {'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("b76db7ac-fdef-11eb-90ee-0242ac150003"), 'level': 1, 'parent_id': UUID("b1865484-fdef-11eb-90ee-0242ac150003"), 'reference_id': UUID("b621b10b-47c8-4492-881d-577e5a7a98af")}, {'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("9a3cdb12-fe09-11eb-a65d-0242ac150003"), 'level': 1, 'parent_id': UUID("b1865484-fdef-11eb-90ee-0242ac150003"), 'reference_id': UUID("09280706-4ab6-459a-86cc-dc953479c356")}, {'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("a53c7522-fe09-11eb-a65d-0242ac150003"), 'level': 2, 'parent_id': UUID("9a3cdb12-fe09-11eb-a65d-0242ac150003"), 'reference_id': UUID("124ece3a-a8ff-415b-8e98-66852d4d7e16")}, {'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("a349cf9a-fe12-11eb-8cc0-0242ac150003"), 'level': 3, 'parent_id': UUID("a53c7522-fe09-11eb-a65d-0242ac150003"), 'reference_id': UUID("e6dbbf9c-ff0b-4337-a9c5-aa9eedfebc07")}]
def to_tree(p = None):
return [{**i, **({'replies':k} if (k:=to_tree(i['id'])) else {})}
for i in comments if i['parent_id'] == p]
full_comments = to_tree()
Output:
[{'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("b1865484-fdef-11eb-90ee-0242ac150003"), 'level': 0, 'parent_id': None, 'reference_id': UUID("e480ae80-89e2-4d38-ba92-570e863fec87"), 'replies': [{'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("b76db7ac-fdef-11eb-90ee-0242ac150003"), 'level': 1, 'parent_id': UUID("b1865484-fdef-11eb-90ee-0242ac150003"), 'reference_id': UUID("b621b10b-47c8-4492-881d-577e5a7a98af")}, {'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("9a3cdb12-fe09-11eb-a65d-0242ac150003"), 'level': 1, 'parent_id': UUID("b1865484-fdef-11eb-90ee-0242ac150003"), 'reference_id': UUID("09280706-4ab6-459a-86cc-dc953479c356"), 'replies': [{'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("a53c7522-fe09-11eb-a65d-0242ac150003"), 'level': 2, 'parent_id': UUID("9a3cdb12-fe09-11eb-a65d-0242ac150003"), 'reference_id': UUID("124ece3a-a8ff-415b-8e98-66852d4d7e16"), 'replies': [{'body': 'holaaaaaaaaaaaaaaaaaaa', 'id': UUID("a349cf9a-fe12-11eb-8cc0-0242ac150003"), 'level': 3, 'parent_id': UUID("a53c7522-fe09-11eb-a65d-0242ac150003"), 'reference_id': UUID("e6dbbf9c-ff0b-4337-a9c5-aa9eedfebc07")}]}]}]}]