#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
внутри aforEach
, который ничего не делает, хотяresult = response;
, скорее всего, делает то, что задумано.2. Это не сработает, если вы используете поиск как найти, верните этот элемент, а не результат функции
3.
find
должно сработать, так как оно вернет значение вызова recusrive.4. Find возвращает значение, которое в данный момент проверяется:
[1].find(() =gt; 5)
вернет 1, а не 5
Ответ №3:
Вы забыли вернуться в свой else, если, но обратите внимание, вы находитесь внутри forEach, так что, возможно, измените его на обычный для или используйте что-то другое