Выход из функции 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 в разных местах.

Ссылки, которые я посоветовал

МОИ ВОПРОСЫ

  1. Что я делаю не так и как мне получить код для возврата первого найденного дубликата?

  2. Что мне не хватает в моем понимании, чтобы сделать эту работу? Разве "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
Другие вопросы по тегам