#javascript #recursion #frontend #callstack #web-frontend
#javascript #рекурсия #интерфейс #стек вызовов #веб-интерфейс #callstack
Вопрос:
Я пытаюсь создать функцию JavaScript, которая рекурсивно ищет файл / каталог в файловой структуре и возвращает этот файл, если он найден. Это пример файловой структуры:
var fileStructure = [
{'pictures': ['picture1.png', {'beach': ['picture2.png']}]},
{'videos': ['video1.mov', 'video2.mov']}
]
В словарях ключ представляет имя каталога, а значение представляет содержимое каталога. Каждый элемент в массивах является файлами. Итак, если я вызвал findFile('picture1.png')
, я должен получить true, или если я вызываю findFile('videos')
, я также должен получить true. Вот что у меня есть на данный момент:
var fileStructure = [{ "music": [{ "acoustic": ["vlad-gluschenko-stars-extended.mp3"] }, { "chinese": ["AlbumArtSmall.jpg", "Folder.jpg", "keys-of-moon-yugen.mp3"] }, { "lofi": ["le-gang-relax-man.mp3", "purple-cat-field-of-fireflies.mp3"] }] }, { "sounds": [{ "campfire": ["fire-crackle.mp3", "fire-rumble.mp3"] }, { "rain": ["rain-heavy.mp3", "rain-light.mp3", "rain-tapping.mp3"] }, { "thunderstorm": ["thunderstorm.mp3"] }, { "wind": ["wind-base.mp3", "wind-howling.mp3", "wind-rattling.mp3"] }] }]
function findFile(fileName, dir) {
for (i in dir) {
let entry = dir[i];
// If entry is a dictionary, unpack into array
if (entry.constructor == Object) {
// If the file being searched for is itself a directory
if (Object.keys(entry).indexOf(fileName) != -1) {
// !!!!! THIS PRINTS BUT THE FUNCTION KEEPS RUNNING !!!!!
console.log(`Found directory: ${fileName}`);
return true;
}
entry = Object.values(entry);
}
// If entry is an array (meaning it is the contents of a directory)
if (Array.isArray(entry)) {
findFile(fileName, entry);
}
// Found file
else if (entry == fileName) {
return true;
}
}
return false;
}
//
fileExists = findFile('tets', fileStructure);
console.log("done", fileExists);
fileExists = findFile('lofi', fileStructure);
console.log("done", fileExists);
В моем коде я вызвал эту функцию следующим образом: fileExists = findFile('lofi', audioLibrary);
Если вы посмотрите на мой комментарий, окруженный восклицательными знаками, эта строка печатается как ожидалось, однако даже после возврата true функция продолжает выполняться и, в конечном счете, переменные FileExists оцениваются как false .
Почему цикл, похоже, продолжается даже после возврата?
Это то, что произошло, когда я добавил точку останова в строку возврата. Как вы можете видеть, цикл выполняется снова.
РЕДАКТИРОВАТЬ: добавлена файловая структура, которую я использую.
Комментарии:
1. ваш код работает нормально. запустите фрагмент кода в вашем вопросе. скорее всего, у вас одна и та же функция запущена в нескольких местах, но, как и здесь, она работает нормально.
2. Вы ничего не делаете с рекурсивным возвращаемым значением
findFile
.return
Завершается только текущий вызов, а не весь стек вызовов.3. Представьте, что рекурсивный вызов
findFile
вызовет любую другую функцию, ее возврат не должен завершать вашу функцию, верно? Здесь то же самое.4. вы, вероятно, хотите
return findFile(fileName, entry);
5. Я не уверен, почему моя функция будет выполняться в нескольких местах, кроме того, когда она вызывает саму себя. В моем случае я получаю вывод: «Найден каталог: lofi», и в этот момент я бы предположил, что FileExists будет иметь значение true. Однако функция продолжается (вероятно, вызывается каким-то образом в другом rplace), и FileExists имеет значение false.
Ответ №1:
Проблема заключалась в том, что я на самом деле не возвращался findFile(fileName, entry);
, поэтому функция выполняла поиск только в одном каталоге, и фактической рекурсии не было (duh lol!) Чтобы решить эту проблему, я отслеживал все подкаталоги в текущем каталоге, в которых выполнялся поиск, с переменной directories
. Затем, как только был проверен последний файл в искомом каталоге, если результаты не были найдены, он попытается выполнить поиск в каждом каталоге в directories
массиве. Если бы ей удалось найти совпадение в любом каталоге, функция вернула бы true.
fileStructure = [{ "music": [{ "acoustic": ["vlad-gluschenko-stars-extended.mp3"] }, { "chinese": ["AlbumArtSmall.jpg", "Folder.jpg", "keys-of-moon-yugen.mp3"] }, { "lofi": ["le-gang-relax-man.mp3", "purple-cat-field-of-fireflies.mp3"] }] }, { "sounds": [{ "campfire": ["fire-crackle.mp3", "fire-rumble.mp3"] }, { "rain": ["rain-heavy.mp3", "rain-light.mp3", "rain-tapping.mp3"] }, { "thunderstorm": ["thunderstorm.mp3"] }, { "wind": ["wind-base.mp3", "wind-howling.mp3", "wind-rattling.mp3"] }] }]
function findFile(fileName, dir) {
var directories = [];
for (i in dir) {
let entry = dir[i];
// If entry is a dictionary, unpack into array
if (entry.constructor == Object) {
// If the file being searched for is itself a directory, then search the dictionary for a directory with the name of fileName
if (Object.keys(entry).indexOf(fileName) != -1) {
return true;
}
entry = Object.values(entry);
}
// If entry is an array (meaning it is the inside of a directory)
if (Array.isArray(entry)) {
directories.push(entry);
}
else if (entry == fileName) {
console.log('Found the file:');
console.log(entry);
return entry;
}
// If item is the last item in directory and no files have matched, begin to search each of the sub-directories
if (i == dir.length - 1) {
for (directory of directories) {
if (findFile(fileName, directory)) {
return true;
}
}
}
}
return false;
}
fileExists = findFile('foo', fileStructure);
console.log('done', fileExists);
fileExists = findFile('lofi', fileStructure);
console.log('done', fileExists);