Рекурсивный поиск возвращает неопределенное

#javascript #recursion

#язык JavaScript #рекурсия

Вопрос:

Я просто практиковался в родном Javascript и столкнулся с этой проблемой. Я создаю виджет комментариев и пытаюсь реализовать кнопку «ответить». Для этого мне нужно перебрать некоторое n вложенных комментариев, чтобы найти правильный и нажать ответ на его атрибут «ответы». До сих пор это мой код:

 const recursiveSearch = (object, target) =gt; {  if(object.id === target) return object;   let result;  if(object.responses.length gt; 0) {  object.responses.forEach(response =gt; {  if(response.id === target) {  result = response;  console.log('match found')  console.log(response)  return response  }     else if(response.responses.length gt; 0) recursiveSearch(response, target)   })   };   console.log('result Is')  console.log(result)   return result  }  

Журналы показывают ожидаемое поведение просто отлично, но при взгляде на оператор end return не определен. Есть какой-нибудь способ обойти это?

Комментарии:

1. Ваша else if ветвь отменяет результат recursiveSearch вызова. return в forEach этом нет смысла.

Ответ №1:

Вы можете значительно упростить свою программу, используя генераторы и многократно используемые функции —

 function first(it) {  for (const v of it)  return v }  function *search(t, id) {  if (t.id == id) yield t  for (const r of t.responses) yield *search(r, id) }  const mydata =   { id: 1, responses: [  { id: 2, responses: [] },  { id: 3, responses: [] },  { id: 4, responses: [  { id: 5, responses: [] },  { id: 6, responses: [] },  { id: 7, responses: [] }  ]},  { id: 8, responses: [  { id: 9, responses: [  { id: 10, responses: [] }  ]}  ]}  ]}  console.log(first(search(mydata, 8))) // { id: 8, responses: [ ... ] } console.log(first(search(mydata, 100))) // undefined 

Еще лучше сделать выбор search в пользу общего, принимающего match и next функционирующего. Теперь вы можете искать входные данные любого типа или формы с любыми полями. Т. е. вы не ограничены только id и responses

 function first(it) {  for (const v of it)  return v }  function *search(t, match, next) {  if (Boolean(match(t))) yield t  for (const r of next(t) ?? []) yield *search(r, match, next) }  function mysearch(t, id) {  return search(t, t =gt; t.id == id, t =gt; t.responses) }  const mydata =   { id: 1, responses: [  { id: 2, responses: [] },  { id: 3, responses: [] },  { id: 4, responses: [  { id: 5, responses: [] },  { id: 6, responses: [] },  { id: 7, responses: [] }  ]},  { id: 8, responses: [  { id: 9, responses: [  { id: 10, responses: [] }  ]}  ]}  ]}  console.log(first(mysearch(mydata, 8))) // { id: 8, responses: [ ... ] } console.log(first(mysearch(mydata, 100))) // undefined 

Комментарии:

1. Вот как выглядит элегантный код!

Ответ №2:

Вы должны вернуться из рекурсивного вызова и result снова назначить переменную.

 const recursiveSearch = (object, target) =gt; {  if (object.id === target) return object;   let result;  if (object.responses.length gt; 0) {  object.responses.forEach(response =gt; {  if (response.id === target) {  result = response;  console.log('match found')  console.log(response)  return response  }   else if (response.responses.length gt; 0) {  result = recursiveSearch(response, target) // lt;--------------------  }  })  };   console.log('result Is')  console.log(result)   return result }  

Вы также можете использовать find вместо forEach . Это более эффективно.

 const recursiveSearch = (object, target) =gt; {  if (object.id === target) return object;   const result = object.responses.find(response =gt; {  if (response.id === target) {  console.log('match found')  console.log(response)  return response  }   else if (response.responses.length gt; 0) {  return recursiveSearch(response, target)  }  })   console.log('result Is')  console.log(result)   return result }  

Комментарии:

1. Это все еще оставляет return response внутри a forEach , который ничего не делает, хотя result = response; , скорее всего, делает то, что задумано.

2. Это не сработает, если вы используете поиск как найти, верните этот элемент, а не результат функции

3. find должно сработать, так как оно вернет значение вызова recusrive.

4. Find возвращает значение, которое в данный момент проверяется: [1].find(() =gt; 5) вернет 1, а не 5

Ответ №3:

Вы забыли вернуться в свой else, если, но обратите внимание, вы находитесь внутри forEach, так что, возможно, измените его на обычный для или используйте что-то другое