Выход из функции JavaScript ES6 не работает с возвратом
ПРОБЛЕМА
Такое ощущение, что все должно быть просто, но я просто не понимаю по какой-то причине. Я решил взять, по-видимому, общий вопрос по собеседованию на программирование, чтобы проверить свои навыки
" Учитывая массив a, который содержит только числа в диапазоне от 1 до a.length, найдите первый дубликат числа, для которого второе вхождение имеет минимальный индекс. Другими словами, если имеется более 1 дублированных чисел, верните число для которого второе вхождение имеет меньший индекс, чем второе вхождение другого числа ".
(источник: https://codefights.com/interview-practice/task/pMvymcahZ8dY4g75q)
Я верю, что у меня правильный код, но я не могу заставить цикл перестать работать. Учитывая пример массива, функция должна возвращать "3", так как это первое повторяющееся число (а не первое увиденное число). Однако, что бы я ни пытался, он либо возвращает 2, либо ошибку.
МОЙ КОД
console.clear();
// create new object to store numbers and counts
var myObj = {};
// array for testing output
var arr1 = [2, 3, 3, 1, 5, 2];
// this will store the "key" number
var firstDuplicateFound = "";
function firstDup(a) {
// loop through each value in numerical array
a.forEach(function(num, i) {
// if associative array has property that is value of current num:
if ( myObj.hasOwnProperty(num) ) {
// increment value by 1
++myObj[num];
firstDuplicateFound = num;
// If first duplicate is found, the code should jump out of the
// loop and return from the function. It should NOT continue
// to process the code in the forEach. At one point, I tried
// "return firstDuplicateFound" here, but it just returned 2.
} else {
// create new array key and assign count of 1
myObj[num] = 1;
}
if (firstDuplicateFound && firstDuplicateFound != NaN) {
return firstDuplicateFound;
}
});
console.log(myObj);
return false;
}
var firstDupNumberFound = firstDup(arr1);
console.log("firstDupNumberFound = " + firstDupNumberFound);
ЧТО Я ПОПЫТАЛ, ЧТО НЕ РАБОТАЛ
Я перепробовал все, что мог придумать. Я прочитал о разнице между перерывом и продолжением и попытался использовать "перерыв" сразу после назначения firstDuplicateFound = num
, но это просто дает мне ошибку о " незаконном объявлении разрыва ":
Uncaught SyntaxError: Недопустимый оператор разрыва в Array.forEach () при firstDup (:15:4) по адресу:49:27 firstDup @ VM80757:15 (анонимно) @ VM80757:49
Я пытался переместить разрыв в другие позиции, но все, что я прочитал, говорит, что разрыв работает только внутри цикла.
Затем я покопался немного глубже и нашел несколько статей, в которых говорилось, что return - это правильное выражение для выхода из функции. Когда будет найден первый дубликат, я хочу, чтобы цикл прекратил выполнение, а функция завершила работу и вернула значение "num" без обработки остальной части числового массива. Такого не бывает. я пытался return
, return firstDuplicateFound
, а также return false
в разных местах.
Ссылки, которые я посоветовал
- Выход из JavaScript "для" цикла с использованием False?
- JavaScript незаконное заявление о разрыве?
- Хеш-таблицы в Javascript - MojaveLinux
- JavaScript перерыв и продолжение - W3Schools
- перерыв - JavaScript | MDN
МОИ ВОПРОСЫ
Что я делаю не так и как мне получить код для возврата первого найденного дубликата?
Что мне не хватает в моем понимании, чтобы сделать эту работу? Разве "firstDuplicateFound" не должно быть лучшим решением? Я действительно пытаюсь получить твердое понимание того, как сделать это правильно.
РЕДАКТИРОВАТЬ
Переполнение стека спросил меня, является ли (этот пост тот, который вы читаете) дубликатом этого поста, и попросил меня объяснить, почему нет, если я не согласен. Это не дубликат - даже если предлагаются похожие ответы, и, похоже, постер другого вопроса работает над аналогичной проблемой - потому что мой вопрос о том, что что-то вообще не работает, тогда как другой вопрос об оптимизации чего-то, что уже работает.
Кроме того, тот, кто ищет "почему не работает", вряд ли увидит "как оптимизировать..." и подумает, что это относится к ним. Что-то должно работать в первую очередь, прежде чем можно будет начать оптимизировать его.
4 ответа
Что пошло не так:
Вы просто не можете вернуться / выйти из цикла forEach. Вот и все. Поэтому, если вы хотите, чтобы код был императивным, а не функциональным (используя break
, continue
, return
) вы должны использовать простой старый стиль для цикла:
function firstDup(array) {
//A hashtable to check for dupes
const hash = {};
// loop through each value in numerical array
for(var n of array){
if(n in hash){
return n;
} else {
hash[n] = true;
}
}
return false;
}
Мой подход:
Насколько я понимаю
возвращает число, для которого второе вхождение имеет меньший индекс, чем второе вхождение другого числа
Просто значит вернуть первый дупе
И это довольно просто:
function dupe(array){
return array.find((n,i) => array.indexOf(n) !== i);
}
или используя набор:
function dupe(array){
const set = new Set;
return array.find(n => set.has(n) || (set.add(n), false));
}
Вы возвращаете значение в функции foreach. Эта функция вызывается для элемента evry в массиве, и его возвращаемое значение игнорируется.
вместо .forEach()
использование for loop
и вернись из него.
console.clear();
// create new object to store numbers and counts
var myObj = {};
// array for testing output
var arr1 = [2, 3, 3, 1, 5, 2];
// this will store the "key" number
var firstDuplicateFound = "";
function firstDup(a) {
// loop through each value in numerical array
for (let i =0; i <a.length; i++) {
const num = a[i]
// if associative array has property that is value of current num:
if ( myObj.hasOwnProperty(num) ) {
// increment value by 1
++myObj[num];
firstDuplicateFound = num;
// If first duplicate is found, the code should jump out of the
// loop and return from the function. It should NOT continue
// to process the code in the forEach. At one point, I tried
// "return firstDuplicateFound" here, but it just returned 2.
} else {
// create new array key and assign count of 1
myObj[num] = 1;
}
if (firstDuplicateFound && firstDuplicateFound != NaN) {
return firstDuplicateFound;
}
}
console.log(myObj);
return false;
}
var firstDupNumberFound = firstDup(arr1);
console.log("firstDupNumberFound = " + firstDupNumberFound);
Вы можете взять хеш-таблицу без каких-либо проверок ownProperty
потому что потенциальные ключи всегда правдивы и нет необходимости проверять другие как напрямую.
Значение для хеш-таблицы просто true
, потому что другое значение не является необходимым, например, count или другое истинное значение.
Это предложение использует быстрый подход, принимая переменные для
- индекс
i
, - длина массива
l
а также - элемент массива
a
без дальнейшего использования свойства собственности.
Для большей скорости, простой while
цикл работает с if
пункт для проверки, был ли элемент посещен или нет.
При посещении вернуть значение, в противном случае установить хэш и продолжить.
function firstDupe(array) {
var hash = Object.create(null),
i = 0,
l = array.length,
a;
while (i < l) {
a = array[i++];
if (hash[a]) {
return a;
}
hash[a] = true;
}
}
console.log(firstDupe([2, 3, 3, 1, 5, 2]));
Хорошо, тогда моя версия
const numbers = [1, 3, 7, 1, 0, 8, 7, 2, 3, 7, 1, 4, 4, 7];
const duplicateMap = numbers
.map((n, i) => {
const index = numbers.findIndex(r => r === n);
return index === i ? null : index;
});
let last = null;
let result = null;
duplicateMap.forEach((n, i) => {
if (n !== null && (last === null || i < last)) {
result = n;
}
last = n !== null ? i : last;
});
console.log(numbers, duplicateMap, result);
Input: [1, 3, 7, 1, 0, 8, 7, 2, 3, 7, 1, 4, 4, 7]
dupMap:[null, null, null, 0, null, null, 2, null, 1, 2, 0, null, 11, 2]
Result: 0