Dostałem to pytanie do wywiadu podczas rozmowy kwalifikacyjnej z jakąś dużą firmą. Poprosili mnie o napisanie funkcji next, która pobiera tablicę jako wartość wejściową i zwraca następną dostępną liczbę.

Liczba o indeksie parzystym w tablicy wskazuje numer następnej liczby w tablicy o indeksie nieparzystym . Na przykład [2,2,1,7,3,5] oznacza, że mamy dwa 2, jeden 7 i 3 5. Tak więc wywołanie next() spowoduje wyświetlenie 2 2 7 5 5 5 po kolei. A gdy nie ma dostępnej liczby, w tym przypadku, gdy zwracany jest trzeci 5, funkcja zgłosi wyjątek.

Więc to pytanie było dość otwarte. Nie określili wyraźnie, w jaki sposób powinienem zaimplementować tę funkcję. Jedynym wymaganiem było osiągnięcie wyżej wymienionego zachowania, tj. Wyprowadzenie kolejnego dostępnego numeru jeden na raz.

Podczas wywiadu pomyślałem, że sensowne byłoby umieszczenie tej funkcji w łańcuchu prototypów Array, abyśmy mogli wywołać tę funkcję bezpośrednio w tablicy takiej jak ta

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 

Zauważyłem, że ludzie mówią, że uczynienie funkcji częścią prototypu Array to zły pomysł. Więc oto inne rozwiązanie

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++];
}

Jednak problem polega na tym, że nie pamięta ostatniego wyjścia i przechodzi do następnego. Zawsze zwróci pierwszy element tablicy.

Zawsze myślałem, że może uda nam się zaimplementować to next jako iterator, ale nie mogłem zaimplementować go sam.

Czy ktoś może mi w tym pomóc?

1
Joji 31 marzec 2020, 21:22

3 odpowiedzi

Najlepsza odpowiedź

Myślę, że naturalnym rozwiązaniem tego problemu byłaby funkcja generatora. Możesz przeczytać o nich więcej tutaj: https://developer.mozilla.org/en- US / docs / Web / JavaScript / Reference / Global_Objects / Generator

Oto moje rozwiązanie. Daj mi znać, jeśli masz jakieś pytania:

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!!

Jest tu trochę cukru składniowego, ponieważ standardowe funkcje generatora js zwracają obiekty takie jak { value, done }. Daj mi znać, jeśli masz jakieś pytania!

1
sdotson 31 marzec 2020, 20:26

Edytuj: ponownie przeczytałem pytanie i wygląda na to, że jest to pytanie typu iteracyjnego. Nadal zostawię odpowiedź taką, jaka jest, ponieważ zawiera wytyczne (bez rekursji), jak również utworzyć odpowiedź.

Podszedłbym do tego w ten sposób:

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]));

Więc w zasadzie wybieramy mnożnik i liczbę, rozkładając resztę tablicy jako taką.

Jeśli nie mamy podanej liczby, zgłaszamy błąd. W przeciwnym razie tworzymy nową tablicę z długością mnożnika i zawartością liczby.

Następnie wykonujemy rekurencyjne wywołanie z resztą tablicy, jeśli zawiera ona jakieś elementy.

Na koniec zwracamy wynik.

Edycja : możesz użyć Array(multiplier).fill(number) zamiast iterować jak w moim przykładzie (Array.from(Array(multiplier), () => number);)

1
Samuli Hakoniemi 31 marzec 2020, 19:17

Cóż, masz część dotyczącą rozwiązywania problemów. Wszystko, co musisz zrobić, to utworzyć zakres, a następnie zachować tymczasowo utworzoną tablicę i bieżący indeks w tym zakresie.

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
Eldar 31 marzec 2020, 18:49