Функция для возврата элементов из массива, где элементы с нечетным индексом повторяются числом по его предыдущему четному индексу - PullRequest
1 голос
/ 31 марта 2020

Я получил этот вопрос при интервью с какой-то крупной компанией. Они попросили меня написать функцию next, которая принимает массив в качестве входного значения и возвращает следующее доступное число.

Число с четным индексом в массиве указывает номер следующего числа в массиве с нечетным индексом. Например, [2,2,1,7,3,5] означает, что у нас есть два 2 с, один 7 и 3 5 с. Таким образом, вызов next() будет выводить 2 2 7 5 5 5 последовательно по одному за раз. И когда нет доступного числа, в этом случае, когда возвращается третий 5, функция выдаст исключение.

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

Во время интервью я подумал, что было бы целесообразно поместить эту функцию в цепочку прототипов Array, чтобы мы могли Вызов этой функции непосредственно для массива, подобного этому

const array = [2, 2, 1, 7, 3, 5];

Array.prototype.next = function() {
  const buffer = [];
  let x;
  let index = 0;
  for (let i = 0; i < this.length; i++) {
    if (i % 2 === 0) {
      x = i;
    } else {
      buffer.push(...new Array(this[x]).fill(this[i]));
    }
  }
  return buffer[index++];
};

console.log(array.next()); // 2
console.log(array.next()); // 2
console.log(array.next()); // 2 

Я заметил, что люди говорят, что плохая идея сделать функцию частью прототипа Array. Итак, вот другое решение

function getNext(array) {
  const buffer = [];
  let x;
  let index = 0;
  for (let i = 0; i < array.length; i++) {
    if (i % 2 === 0) {
      x = i;
    } else {
      buffer.push(...new Array(array[x]).fill(array[i]));
    }
  }
  return buffer[index++];
}

Однако проблема в том, что он не запоминает последний вывод и переходит к следующему. Он всегда будет выводить первый элемент в массиве.

Я всегда думал, что, может быть, мы сможем реализовать этот next в качестве итератора, но я сам не смог его реализовать.

Может кто-нибудь мне помочь с этим?

Ответы [ 3 ]

1 голос
/ 31 марта 2020

Ну, у вас есть часть для решения проблем. Все, что вам нужно сделать, это создать область, а затем сохранить созданный вами массив и текущий индекс в этой области.

const array = [2, 2, 1, 7, 3, 5];

function sequencer(arr) {
  const actualArray = []
  let currentIndex = 0;
  for (let i = 0; i < arr.length; i++) {
    if (i % 2 === 0) {
      x = i;
    } else {
      actualArray.push(...new Array(arr[x]).fill(arr[i]));
    }
  }
  return function() {
    if (currentIndex >= actualArray.length) throw new Error("execced array length")
    return actualArray[currentIndex++];
  }
}
let arrSequencer = sequencer(array);
for (let i = 0; i < 7; i++) {
  console.log(arrSequencer());
}
1 голос
/ 31 марта 2020

Редактировать: Я снова прочитал вопрос, и кажется, что это вопрос итераторского типа. Я все равно оставлю свой ответ как есть, поскольку он дает руководство (без рекурсии) о том, как также создать ответ.

Я бы подошел к нему так:

const next = (arr) => {
  const [multiplier, number, ...rest] = arr;

  if (!number) {
    throw Error('No next number specified');
  }

  const currentOne = Array.from(Array(multiplier), () => number);
  const nextOne = (rest.length) ? next(rest) : [];
  return currentOne.concat(nextOne);
}

console.log(next([2,1,3,2,4,3]));
console.log(next([2,1,3,2,4,3,5]));

Таким образом, в основном мы выбираем множитель и число, расширяя остаток массива как таковой.

Если у нас не указано число, мы бросаем ошибку. В противном случае мы создаем новый массив с длиной множителя и содержанием числа.

Затем мы делаем рекурсивный вызов с остальной частью массива, если он содержит какие-либо элементы.

И, наконец, мы вернуть результат.

Редактировать : Вы можете использовать Array(multiplier).fill(number) вместо итерации, как в моем примере (Array.from(Array(multiplier), () => number);)

1 голос
/ 31 марта 2020

Я думаю, что естественным решением этой проблемы была бы функция генератора. Вы можете прочитать больше о них здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator

Вот мое решение. Дайте мне знать, если у вас есть какие-либо вопросы:

const generatorFunc = function* (arr) {
  let i = 0;
  while (i < arr.length) {
    yield arr[i];
    i++;
  } 
};

const buildIterator = (arr) => {
  const generatedArr = arr.reduce((acc, item, itemIndex) => {
    const isEven = itemIndex % 2 === 0;
    if (isEven) {
      const value = arr[itemIndex + 1];
      const iterationCount = item;
      return acc.concat(Array(iterationCount).fill(value));
    };
    return acc;
  }, []);
  const generator = generatorFunc(generatedArr);
  return {
    next: () => {
      const nextIteration = generator.next();
      if (nextIteration.done) {
        throw new Error('No more items in array');
      }
      return nextIteration.value;
    }
  };
};

const myIterator = buildIterator([2,2,1,7,3,5]);

console.log(myIterator.next()); //2
console.log(myIterator.next()); //2
console.log(myIterator.next()); //7
console.log(myIterator.next()); //5
console.log(myIterator.next()); //5
console.log(myIterator.next()); //5
console.log(myIterator.next()); // ERROR!!

Здесь есть немного синтактики c сахара, поскольку стандартные js функции генератора возвращают объекты, подобные { value, done }. Дайте мне знать, если у вас есть какие-либо вопросы!

...