интервьюер: Приветствую, хотите кофе или что-нибудь еще? Нужен перерыв?


я: Нет, кажется я уже выпил достаточно кофе!


интервьюер: Отлично, отлично. Как вы относитесь к написанию кода на доске?


я: Я только так код и пишу!


интервьюер: ...


я: Это была шутка.


интервьюер: OK, итак, вам знакома задача "fizz buzz"?


я: ...


интервьюер: Это было да или нет?


я: Это что-то вроде "Не могу поверить, что вы меня об этом спрашиваете."


интервьюер: OK, значит, нужно напечатать числа от 1 до 100, только если число делится нацело на 3, напечатать слово "fizz", если на 5 — "buzz", а если делится на 15, то — "fizzbuzz".


я: Я знаю эту задачу.


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


я: ...


интервьюер: Вот маркер и губка.


я: [задумался на пару минут]


интервьюер: Вам нужна помощь, чтобы начать?


я: Нет, нет, все в порядке. Итак, начнем с пары стандартных импортов:


import numpy as np
import tensorflow as tf

интервьюер: Эм, вы же правильно поняли проблему в fizzbuzz, верно?


я: Так точно. Давайте обсудим модели. Я думаю тут подойдет простой многослойный перцептрон с одним скрытым слоем.


интервьюер: Перцептрон?


я: Или нейронная сеть, как вам угодно будет называть. Мы хотим чтобы на вход приходило число, а на выходе была корректное "fizzbuzz" представление этого числа. В частности, мы хотим превратить каждый вход в вектор "активаций". Одним из простых способов может быть конвертирование в двоичный вид.


интервьюер: Двоичный вид?


я: Да, ну, знаете, единицы и нули? Что-то вроде:


def binary_encode(i, num_digits):
    return np.array([i >> d & 1 for d in range(num_digits)])

интервьюер: [смотрит на доску с минуту]


я: И нашим выходом будет унитарное кодирование fizzbuzz представления числа, где первая позиция означает "напечатать как есть", второе означает "fizz" и так далее.


def fizz_buzz_encode(i):
    if   i % 15 == 0: return np.array([0, 0, 0, 1])
    elif i % 5  == 0: return np.array([0, 0, 1, 0])
    elif i % 3  == 0: return np.array([0, 1, 0, 0])
    else:             return np.array([1, 0, 0, 0])

интервьюер: OK, этого, кажется, достаточно.


я: Да, вы правы, этого достаточно для настройки. Теперь нам нужно сгенерировать данные для тренировки сети. Это будет нечестно использовать числа от 1 до 100 для тренировки, поэтому давайте натренируем на всех оставшихся числах вплоть до 1024:


NUM_DIGITS = 10
trX = np.array([binary_encode(i, NUM_DIGITS) for i in range(101, 2 ** NUM_DIGITS)])
trY = np.array([fizz_buzz_encode(i)          for i in range(101, 2 ** NUM_DIGITS)])

интервьюер: ...


я: Теперь нашу модель нужно адаптировать для tensorflow. Сходу я не сильно уверен какую толщину слоя взять, может 10?


интервьюер: ...


я: Да, пожалуй 100 будет лучше. Мы всегда можем изменить это позже:


NUM_HIDDEN = 100

Нам понадобится входная переменная шириной в NUM_DIGITS, и выходная переменная с шириной в 4:


X = tf.placeholder("float", [None, NUM_DIGITS])
Y = tf.placeholder("float", [None, 4])

интервьюер: Как далеко вы планируете зайти с этим?


я: Ах, всего два слоя — один скрытый слой и один слой для вывода. Давайте используем случайно-инициализированные веса для наших нейронов:


def init_weights(shape):
    return tf.Variable(tf.random_normal(shape, stddev=0.01))

w_h = init_weights([NUM_DIGITS, NUM_HIDDEN])
w_o = init_weights([NUM_HIDDEN, 4])

И мы готовы определить нашу модель. Как я сказал ранее, один скрытый слой, и, давайте используем, ну, не знаю, ReLU активацию:


def model(X, w_h, w_o):
    h = tf.nn.relu(tf.matmul(X, w_h))
    return tf.matmul(h, w_o)

Мы можем использоваться softmax кросс-энтропию как нашу функцию стоимости и попробовать минимизировать её:


py_x = model(X, w_h, w_o)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(py_x, Y))
train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost)

интервьюер: ...


я: И, конечно, предсказание будет просто наибольшим выходом:


predict_op = tf.argmax(py_x, 1)

интервьюер: Пока вы не заблудились, проблема, которую вы должны были решить это генерация fizz buzz для чисел от 1 до 100.


я: Ох, отличное замечание, predict_op функция вернет число от 0 до 3, но мы же хотим "fizz buzz" вывод:


def fizz_buzz(i, prediction):
    return [str(i), "fizz", "buzz", "fizzbuzz"][prediction]

интервьюер: ...


я: Теперь мы готовы натренировать модель. Поднимем tensorflow сессию и проинициализируем переменные:


with tf.Session() as sess:
    tf.initialize_all_variables().run()

Запустим, скажем, 1000 эпох тренировки?


интервьюер: ...


я: Да, наверное этого будет мало — пусть будет 10000, чтобы наверняка.


Ещё, наши данные для тренировки последовательны, что мне не нравится, так что давайте размешаем их на каждой итерации:


for epoch in range(10000):
    p = np.random.permutation(range(len(trX)))
    trX, trY = trX[p], trY[p]

И, каждая эпоха будет тренировать в пачках по, я не знаю, ну пусть 128 входов.


BATCH_SIZE = 128

В итоге, каждый проход будет выглядеть так:


    for start in range(0, len(trX), BATCH_SIZE):
        end = start + BATCH_SIZE
        sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end]})

и потом мы можем вывести погрешность тренировочных данных, ведь почему бы и нет?


    print(epoch, np.mean(np.argmax(trY, axis=1) ==
                         sess.run(predict_op, feed_dict={X: trX, Y: trY})))

интервьюер: Вы серьёзно?


я: Да, мне кажется это очень полезно видеть, как прогрессирует точность.


интервьюер: ...


я: Итак, после того, как модель натренирована, время fizz buzz. Наш вход будет всего лишь двоичное кодирование числе от 1 до 100:


numbers = np.arange(1, 101)
teX = np.transpose(binary_encode(numbers, NUM_DIGITS))

И затем, наше вывод это просто fizz_buzz функция, применённая к выходной модели:


teY = sess.run(predict_op, feed_dict={X: teX})
output = np.vectorize(fizz_buzz)(numbers, teY)

print(output)

интервьюер: ...


я: И это будет ваш fizz buzz!


интервьюер: Этого достаточно, правда. Мы с вами свяжемся.


я: Свяжемся, звучит многообещающе.


интервьюер: ...


Постскриптум


Я не получил эту работу. Но я попробовал на самом деле запустить этот код (код на Github), и, оказалось, что он даёт несколько неправильный вывод! Большое спасибо, машинное обучение!


In [185]: output
Out[185]:
array(['1', '2', 'fizz', '4', 'buzz', 'fizz', '7', '8', 'fizz', 'buzz',
       '11', 'fizz', '13', '14', 'fizzbuzz', '16', '17', 'fizz', '19',
       'buzz', '21', '22', '23', 'fizz', 'buzz', '26', 'fizz', '28', '29',
       'fizzbuzz', '31', 'fizz', 'fizz', '34', 'buzz', 'fizz', '37', '38',
       'fizz', 'buzz', '41', '42', '43', '44', 'fizzbuzz', '46', '47',
       'fizz', '49', 'buzz', 'fizz', '52', 'fizz', 'fizz', 'buzz', '56',
       'fizz', '58', '59', 'fizzbuzz', '61', '62', 'fizz', '64', 'buzz',
       'fizz', '67', '68', '69', 'buzz', '71', 'fizz', '73', '74',
       'fizzbuzz', '76', '77', 'fizz', '79', 'buzz', '81', '82', '83',
       '84', 'buzz', '86', '87', '88', '89', 'fizzbuzz', '91', '92', '93',
       '94', 'buzz', 'fizz', '97', '98', 'fizz', 'fizz'],
      dtype='<U8')

Наверное, нужно взять более глубокую нейронную сеть.

Поделиться с друзьями
-->

Комментарии (127)


  1. Randl
    24.05.2016 01:52
    +7

    Надо было делать на brainfuck. Тогда бы взяли


  1. gena_glot
    24.05.2016 02:13
    -50

    Идея fizz buzz — проверить умение логически мыслить и читать тело задачи.
    Задача решается в два if. Если число делится на 3 и на 5, значит оно делится и на 15. Написать в два if не так просто, учитывая output. Но надо сделать именно в два if (else стейтмент можно вводить).

    Именно так задача давалась в оригинале.
    Попробуйте решить строго в два if


    1. encyclopedist
      24.05.2016 02:19
      +48

      Вы это серьёзно? (Или ваш комментарий настолько тонок, что я не понимаю?)


      1. gena_glot
        24.05.2016 04:25
        -31

        Еще раз условие задачи для тех кто не понял:
        есть понятие пробы. Проба позволяет узнать значение.
        есть if () — в скобках мы пробируем значение.
        нам надо написать программу, которая:
        1. если число делится на 3 выводит «fizz»
        2. если число делится на 5 выводит «buzz»
        3. если число делится на 3 и на 5 выводит «fizzbuzz».
        4. если число не делится на 3, на 5, на 3 и на 5 НЕ выводит ни fizz, ни buzz, а выводит само число

        Example output:
        1 2 fizz 4 buzz 6 7… 14 fizzbuzz 16 17

        Попробуйте Randl, не знаю С++, что у вас выведется на экране.

        Можно написать
        for { if else; if else }
        можно
        for { if; if }
        можно
        for { if else; if}
        и т.п.
        оператор print()
        Попробуйте честно решить


        1. IIvana
          24.05.2016 04:38
          +3

          Вангую, что вам опять посыпятся минусы, но вместо этого я встречно предложу вам решить эту задачку вообще без проб, проверок и условий. Раз уж вы так настаиваете. Попробуйте честно решить (С).

          алгоритм под спойлером :)
          Заводим мутабельный массив, заполняем числами, потом пробегаемся по нему с 3 с шагом 3 — пишем в значение элемента физз, вторая пробежка — с 5 с шагом 5 — пишем базз, третья — с 15 с шагом 15 — пишем физзбазз.


          1. IIvana
            24.05.2016 04:46
            +6

            ЗЫ и похоже, ваш алгоритм как и у героя статьи, тоже эвристический :)

            Example output:
            … 6 ....


          1. VolCh
            24.05.2016 07:27

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


            1. IIvana
              24.05.2016 07:50
              +1

              Если заполнять пустой строкой, то потом все равно придется делать проверку — на пустоту строки, и выводить индекс. А у нас надо же без проверок :) Ну, кроме проверки на прекращение цикла — но ее и постановщик ограничений за проверку не считает. А так, я уже под впечатлением от обсуждения создал тему на одном форуме — с ограничениями без единого if, switch / case, тернарного оператора, любых циклов for, while, do, goto, foreach и прочих функциональных мапов, фолдов и фильтров (допустим, на С++) — решить эту задачку.


              1. kasperos
                24.05.2016 10:55
                +4

                print(«1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz ...»);
                так сойдет?


                1. vladshulkevich
                  24.05.2016 22:30

                  Давайте зачетку


              1. silvansky
                24.05.2016 11:23
                +1

                Хм, а если делать на шаблонах? Работа компилятора считается? =)


          1. DennyRolling
            24.05.2016 09:59
            +6

            ну что же так, массив, числа какие-то: только рекурсия темплейтов, только хардкор


            1. k06a
              25.05.2016 08:57
              +1

              Чуть упростил принтер https://gist.github.com/k06a/f3cbc6533dec54bb301a880c8f231aa4


              1. DennyRolling
                25.05.2016 23:42
                +2

                а я тряхнул стариной и зафигачил на дефайнах, раскрывающихся в сто тернарных операторов (каждый из которых может быть вычислен компилятором): http://codepad.org/5t1na6Rs


                1. nick_nsk
                  26.05.2016 10:23
                  -2

                  Давайте зачетку


          1. 183614956
            24.05.2016 13:13
            -2

            Зачем просматривать весь массив 3 раза, когда можно один раз?


            1. mayorovp
              24.05.2016 14:00

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


          1. neosapient
            28.05.2016 17:30
            -3

            // Могу решить вообще без if-else!

            // Достаточно подготовить массив и обращаться по индексу.

            #include
            #include

            char *arr[]={«1», «2», «fizz», «4», «buzz», «fizz», «7», «8», «fizz», «buzz», «11», «fizz», «13», «14», «fizzbuzz», «16», «17», «fizz», «19», «buzz», «fizz», «22», «23», «fizz», «buzz», «26», «fizz», «28», «29», «fizzbuzz», «31», «32», «fizz», «34», «buzz», «fizz», «37», «38», «fizz», «buzz», «41», «fizz», «43», «44», «fizzbuzz», «46», «47», «fizz», «49», «buzz», «fizz», «52», «53», «fizz», «buzz», «56», «fizz», «58», «59», «fizzbuzz», «61», «62», «fizz», «64», «buzz», «fizz», «67», «68», «fizz», «buzz», «71», «fizz», «73», «74», «fizzbuzz», «76», «77», «fizz», «79», «buzz», «fizz», «82», «83», «fizz», «buzz», «86», «fizz», «88», «89», «fizzbuzz», «91», «92», «fizz», «94», «buzz», «fizz», «97», «98», «fizz»};

            void echo(int i)
            {
            printf("%i -> %s\n", i, arr[i-1]);
            }

            int main(void) {
            echo(rand()%100 + 1);
            return 0;
            }

            // жаль, за мой ответ голосовать нельзя ))


            1. kasperos
              30.05.2016 09:07
              +1

              Немного более универсальный подход с массивом:

              // 0,1,2… 14
              string array a[15]={«fizzbuzz»,«num»,«num»,«fizz»,«num»,«buzz»,«fizz»,«num»,«num»,«fizz»,«buzz»,«num»,«buzz»,«num»,«num»};

              string func(int n){
              int i=n%15;
              if (a[i]==«num») then return string(n);
              else return a[i];
              }

              язык описания немного намешан, но думаю что принцип ясен, если использовать подмену (скрытая проверка условия)
              можно избавиться от явного условия «if». Необходимо только на вход подавать целое число больше нуля.


              1. kasperos
                30.05.2016 09:47

                Чуть позже дошло что нужно в первом присваивании получать сразу строку из массива для того чтобы второй раз по массиву не елозить.
                *
                string s=a[n%15];
                if(s==«num») then return string(n);
                else return s;
                *


        1. encyclopedist
          24.05.2016 10:17
          +29

          Вам ставят минусы не потому, что с вами не согласны или не поняли условие задачи, а потому, что пост совсем не о том, как решать FizzBuzz. Вообще.


          1. Wesha
            24.05.2016 22:16
            +1

            пост совсем не о том, как решать FizzBuzz. Вообще.

            Это-то понятно, но дело в том, что настоящий программист просто физически не способен пройти мимо интересной задачи!


        1. SCareAngel
          24.05.2016 13:13
          +1

          Без if

          import math

          def fizzbuzz(i):
            return [str(i), 'fizz', 'buzz', 'fizzbuzz'][3 — math.ceil((i % 3) / 2) * 2 — math.ceil((i % 5) / 4)]

          for i in range(1, 100):
            print(fizzbuzz(i))


          1. DrNemo
            24.05.2016 17:55
            +3

            вы тестировали код?)


            1. SCareAngel
              26.05.2016 18:16

              Одним глазком


              1. Wesha
                26.05.2016 18:24

                Моё почтение, Михаил Илларионович!


                1. SCareAngel
                  26.05.2016 18:27
                  +1

                  Не намекаете ли вы на то, что у меня 'fizz' и 'buzz' поменялись местами?


                  1. Wesha
                    26.05.2016 18:57

                    Нет, это старая шутка из серии "весь вечер Кутузов строил девушкам глазки глазок" ;)


    1. Randl
      24.05.2016 02:36
      +4

      Идея FizzBuzz — отсеять совсем неумеющих программировать совсем.
      Написать его даже в 2 if без else несложно.


      С++. Может подумаете самостоятельно?
        for (uint8_t i = 1;  i <= 100; ++i) {
          std::string s = std::to_string(i);
          if (!(i%3)) {
            std::cout << "fizz";
            s = "";
          }
          if (!(i%5)) {
            std::cout << "buzz";
            s= "";
          }
          std::cout << s << std::endl;
        }


      1. Amareis
        24.05.2016 03:25
        +6

        По-моему тут куда лучше было бы условие написать честно, i%3 == 0. Читаемость значительно повысится, а символов печатать всего на два пробела больше.


        1. tangro
          24.05.2016 09:44
          +7

          Да вообще эти сишные хаки в стиле «я знаю, что 0 это тоже самое, что NULL и тоже самое что false» — раздражают. if тестирует условие, так будьте добры — пишите в if условия!


        1. Randl
          24.05.2016 11:29
          +1

          Верно. Просто сначала написал i%3, а потом изменил на противоположное условие и добавил !. Вот и вышло не очень красиво


      1. gena_glot
        24.05.2016 05:40
        +1

        Задача давалась Джоном Холландом отцом генетических алгоритмов, в 70-х годах.

        Ключевой момент вашего решения — операция s = ""

        Обычно схема fizzbuzz идет следующим образом:
        1. Напишите fizzbuzz — написал в 3 if.
        2. Напишите fizzbuzz в 2 if. Пишут что и вы.
        3. Избавьтесь от изменения переменных. Тут продолжите свои размышления.
        Если вы считаете, что в условиях 3 задача не решается — докажите что решений нет. Если решается — решите.

        Неумеющий программировать — уходит на пункте 1
        Умеющий программировать — решает пункт 2
        Математик — решает пункт 3.

        Правило следующие:
        if { block } then { block } else { block}; if {block} then {block} else {block} — два if
        if; if — два if
        if then else if; if — недопустимо. Три if

        промежуточные результаты можно сохранить в неизменяюю переменную.
        Нельзя менять переменную, в вашем случае s = "" недопустимо для пункта 3.
        можно вычислять любые выражения, битовые сдвиги, числа — все допустимо.
        Обрамляющий цикл — классический for или while.


        1. senia
          24.05.2016 06:07

          В такой формулировке не понятно зачем там второй if.


          1. gena_glot
            24.05.2016 06:49

            Ну у нас максимум два if. Задача Холланда, не моя.
            максимум два раза можно узнать результат — это значит пробу сделать.
            if (i mod 3 = 0) — опробировали 1 раз
            if (i mod 3 = 0 && i mod 5 = 0) — опробировали 1 раз.
            Результат первой пробы можно использовать во второй пробе.


            1. TheTony
              24.05.2016 08:00

              но результат первой пробы — надо сохранить в переменную, разве нет?


            1. senia
              24.05.2016 10:14

              И как вы с такими if отличите fizz от fizzbuzz?
              i == 3:
              i mod 3 = 0 == true
              i mod 3 = 0 && i mod 5 = 0 == true
              i == 15
              i mod 3 = 0 == true
              i mod 3 = 0 && i mod 5 = 0 == true


              1. SkidanovAlex
                24.05.2016 19:52
                +1

                > i == 3:
                >…
                > i mod 3 = 0 && i mod 5 = 0 == true

                это неверно


                1. senia
                  24.05.2016 21:18

                  Действительно. Там же &&, а не || — перепутал.
                  Тогда тот же вопрос про n vs buzz: 2 — false, false; 5 — false, false. Суть не изменилась.


                  1. SkidanovAlex
                    25.05.2016 00:35

                    Ну да, автор комментария показывал пример того, что он понимает под двумя if-ами, он не предлагал рабочее решение для задачи.
                    Я подозреваю, что в задаче подразумевается ответ «решения нет», который доказывается как-нибудь через то, что у нас грубо говоря есть только три листа в дереве ветвлений, а надо четыре. Но задачу надо очень сильно формализовать, чтобы убить всякие решения с масками, индексами в массивы итд.


                    1. senia
                      25.05.2016 07:53

                      На самом деле gena_glot просто несет что-то странное. Выше решение с 2 if привели. Убрать из него изменяемые переменные — задача чисто механическая (просто понадобится переменная s2): тыц, тыц.


            1. Gokudera
              28.05.2016 17:29

              if (i mod 3 = 0) — fizz
              if (i mod 3 = 0 && i mod 5 = 0) — fizzbuzz
              buzz?


        1. Scf
          24.05.2016 09:21
          +2

          Вот вам вариант вообще без if-ов.


          object FizzBuzz {
            def main(args: Array[String]) = {
              val fb = Array[String](
                "fizzbuzz", "fizz", "fizz", "fizz", "fizz",
                "buzz", "a", "a", "a", "a",
                "buzz", "a", "a", "a", "a")
              for (i <- 1 to 100) {
                println(fb(5 * (i % 3) + i % 5).replace("a", i.toString))
              }
            }
          }


          1. erlyvideo
            24.05.2016 11:46
            -1

            очень плохой ответ. Элегантный, хакерский, но такой код должен идти с нормальным текстом в комментарии и объяснении, зачем был выбран такой сложный алгоритм


          1. Ogoun
            24.05.2016 12:41
            +1

            Можно добавить один if чтобы не выводить пустые строки, и сократить массив.

            variants = ('', 'fizz', 'buzz', 'fizzbuzz')
            for i in range(101):
                v = variants[(i % 3 == 0) + (i % 5 == 0) * 2]
                if v != '':
                    print("{0}: {1}".format(i, v))
            


            1. Scf
              24.05.2016 13:09

              Какие такие пустые строки? Мой вариант пустрых строк не выводит…
              Но про неявную конверсию bool -> int — хорошая идея.


              1. Ogoun
                24.05.2016 13:25
                +2

                Да, прошу прощения, недочитал задачу, решил что нужно вывести только если делятся, а не с заменой.
                Соответственно решение с поправкой будет еще короче:

                variants = ('{}', 'fizz', 'buzz', 'fizzbuzz')
                print("\n".join([variants[(i % 3 == 0) + (i % 5 == 0) * 2].format(i) for i in range(101)]))
                


            1. Scf
              24.05.2016 13:23

              О, совсем забыл — в скале нет имплиситных конвертаций булеана в инт. Не С++ все же.


            1. Demogor
              25.05.2016 19:55
              +1

              C 1 if'ом можно вообще без хитрых алгоритмов:

              var test=(e)=>{
              	var q={
              		3: 'fizz',
              		5: 'buzz',
              		15: 'fizzbuzz'
              	};
              
              	var result=e;
              	for(var i in q){
              	   if(e%i==0){
              		 result=q[i];
              	   }
              	}
              	return result;
              };
              
              var t=[];
              for(var i=0; i<100; i++) t.push(test(i));
              console.log(t.join(' '))
              


              Вот без — изящно.


        1. findoff
          24.05.2016 10:56
          +3

          На правах наркомании и отсутствия чувства юмора…

          console.clear();
          // что бы совсем без if'ов и пустых строк...
          var a = [
          	function(){},
          	console.log.bind(null, 'fizz'),
          	console.log.bind(null, 'buzz'),
          	console.log.bind(null, 'fizz buzz'),
          ];
          for(var i=1; i<=100; ++i){
                  // получаем в виде битов, через черную магию -> складываем a+b*2 -> и соотвественно выводим [ничего,1е,2е,оба]
          	a[Math.floor(((i-1)%3)/2) + Math.floor(((i-1)%5)/4)*2](i);
          }
          


        1. Randl
          24.05.2016 11:59
          +2

          Без if'ов вообще:


          Зато с массивом
            for (uint8_t i = 1;  i <= 100; ++i) {
              std::array<std::string, 4> print = {std::to_string(i), "fizz", "buzz", "fizzbuzz"};
              bool three = i % 3 == 0, five = i % 5 == 0;
              std::cout << print[three +five * 2] << std::endl;
            }


    1. erlyvideo
      24.05.2016 11:45

      идея fizz buzz прежде всего в том, что бы проверить, способен ли программист услышать менеджера и сделать минимально и достаточно необходимое количество действий, что бы решить задачу так, как его попросили. Без tensorflow.

      На fizzbuzz как раз всплывают такие случаи, когда человек вместо двух аккуратных ифов, которые он делает с первого раза, возникают монстры типа нейросети.

      Но статья очень смешная.


      1. Neikist
        28.05.2016 17:30
        +1

        А если человека берут работать с нейросетями? Тогда логично ведь делать описанным в статье способом.


    1. vladshulkevich
      24.05.2016 13:13
      +6

      interviewer detected


    1. Artemeey
      24.05.2016 21:48

      Почему на ваш ответ столько минусов?


      1. Amareis
        24.05.2016 21:55

        Проблема в том, что статья-то совсем не про физзбазз, это такое введение в тензорфлоу. Да и вообще-то задачка-то нужна только для того, чтобы выяснить умеет ли человек код писать.


        1. Wesha
          24.05.2016 22:20

          и вообще-то задачка-то нужна только для того, чтобы выяснить умеет ли человек код писать.

          Вспомнилось:


          Мужик в лесу заблудился, орёт "Ау! Ау!"
          Подходит медведь: "Мужик, чего орешь?"
          Мужик: "Заблудился, может кто услышит."
          Медведь: "Ну я услышал. Тебе легче стало?"

          Человек явно умеет решать задачи при помощи TensorFlow. Вам легче стало? ;)


  1. kreon
    24.05.2016 02:22
    +29

    Без go, nodejs и микросервисов — не тру ;)


  1. brainhack
    24.05.2016 02:24
    +16

    Это была великолепная статья. Чаще бы такое попадалось:(


  1. Randl
    24.05.2016 02:35

    del


  1. IIvana
    24.05.2016 03:51
    +24

    Правильно, что не взяли на работу — требовался детерминированный алгоритм, а не эвристика, которая в результате ошиблась :)


  1. bingo347
    24.05.2016 03:56
    -21

    на js в одну строку

    for(let s, i = 0; i < 100; i++) s = '', (i % 3 || (s += 'Fizz')), (i % 5 || (s += 'Buzz')), console.log(s || i);
    

    и незачем мудрить


    1. Smagold
      24.05.2016 08:32
      +8

      У вас он с нуля считает ;)
      Статья кстати была не про это, в интернете и так вариантов куча, от красивых до производительных.


    1. scronheim
      24.05.2016 08:32

      нужно напечатать числа от 1 до 100


    1. vintage
      24.05.2016 09:12
      +11

      Вы пробелы убрать забыли.


    1. mayorovp
      24.05.2016 09:48
      +7

      Ваш код не соответствует вашему же призыву ("и незачем мудрить").


    1. Daniro_San
      24.05.2016 14:34

      Раз уж на то пошло, то почему бы и нет…

      input([ "FizzBuzz" if not x%3 and not x%5 else "Fizz" if not x%3 else "Buzz" if not x%5 else x for x in range(1, 101)])
      


      как то писал и C++ однострочник, но там настоящий ужас


    1. Daniro_San
      24.05.2016 14:37

      И да, у вас тело на одной строке с условием цикла — это не совсем кошерный однострочник


  1. IIvana
    24.05.2016 04:01
    +1

    Не, на самом деле герой статьи молодец :) За мой опыт устройства на работу меня тоже далеко не во все места брали, но как я потом радовался, что меня не взяли в те места! Если это реальная история, то все закончилось лучшим исходом — и для героя, и для компании :)


  1. brainick
    24.05.2016 04:42
    +3

    Остаётся только добавить, что Joel Grus автор отличной книги по машинному обучению http://shop.oreilly.com/product/0636920033400.do которую при некотором усилии можно, сами понимаете как достать.


  1. Demogor
    24.05.2016 07:54
    +13

    А вывод простой: хочешь провалить интервью — покажи интервьюеру, что он ламер.


    1. khim
      24.05.2016 11:58
      +6

      Правда, но не совсем. Тут немного другое. Не «покажи интервьюеру, что он ламер», а «покажи интервьюеру, что ты на него плевать хотел».

      Я пару раз встречался с людьми, которые обнаруживали ошибки и неточности в моих вопросах и задачах. Было неудобно, да, но на оценку и шансы принятия на работу это влияет только положительно.

      А вот когда кандидат сознательно манкирует вопросами интервьюера и вместо решения задачи, о которой его просили, демонстрирует какой он умный и хороший, но не порождает решения, которого от него ждут… это чистый «No Hire».

      Ну представьте себе: вы приняли такого на работу, попросили написать что-нибудь… ну мелочь какую-нибудь, но такую, без которой у вас убытков на миллионы, а он вместо этого проделал массу бессмысленной работы, но задачу не решил и в убытки вы таки влетели… зачем оно вам?


      1. Randl
        24.05.2016 18:05

        ИМХО давать FizzBuzz на интервью — это дурной тон. Ещё б спросили сколько настройщиков пианино в мире.


        1. Scf
          24.05.2016 18:11
          +4

          Вы недооцениваете количество людей, которые эту задачу не решат. В моей практике собеседований сложные вопросы просто не нужны — достаточно послушать, что кандидат расскажет про свой проект и поспрашивать основы + простейшие задачки типа "найти максимальную глубину двоичного дерева".


          1. Randl
            24.05.2016 18:22

            Во первых, вопрос в том, на какую позицию интервью. Одно дело джуниор, другое — миддл или сениор.
            Во вторых, я имел ввиду не сложность задачи, а её разрекламированность. Ну серьёно, о FizzBuzz знают все. Имейте совесть придумать аналогичную простую задачу если это то, что вам нужно. Сам факт вопроса "вам знакома задача "fizz buzz"?" означает, что интервьюер ожидает, что задача мне знакома.


            1. khim
              24.05.2016 19:00
              +3

              Сам факт вопроса «вам знакома задача „fizz buzz“?» означает, что интервьюер ожидает, что задача мне знакома.
              И что? Вам теперь сложно её написать?

              Задача может быть сколько угодно «широко разрекламированной», но даже при всём при этом соискатели, в большинстве своём — неспособны её написать. Вы можете? Отлично — возьмите и напишите, а не ломайте комедию.

              Во первых, вопрос в том, на какую позицию интервью. Одно дело джуниор, другое — миддл или сениор.
              Вот как раз для сениора — эта задачка в самый раз.

              Ибо встречал я таких «сениоров»: могут часами песни петь про всякие разные супер-пупер технологии (я и словей-то таких не знаю), рассказывать как у них команда «бороздит просторы Большого театра»… написать FuzzBuzz — не могут. Вот никак.

              Обычно дальнейший разговор показывает, что человек последние N лет код не пишет от слова совсем и только «руководит проектами». Ну и на что он претендует, пытаясь устроиться на инженерную должность? Что? У нас не было вакансий «чистого менеджера?»… Действительно не было — потому что подобных должностей у нас нет, извините.

              P.S. Я был бы счастлив перенестись как-нибудь ночью в мир где FuzzBuzz на собеседовании реально смысла не имеет ибо все соискатели способны его написать за 2 минуты. В нашем, реальном, мире — всё не так. Увы.


              1. Randl
                24.05.2016 19:30

                И что? Вам теперь сложно её написать?

                Не сложно. Но я ожидаю задачи своего уровня на собеседовании. И уровня потенциальной работы. И ожидаю, что интервью будет не с первой строчки гугла. И допускаю, что такая задача вкупе с поведением интервьюра может вызвать желание немного над ним поиздеваться.


                Вот как раз для сениора — эта задачка в самый раз.

                Так дайте ему сложную задачу. Кто не разбирается — одинаково обе не решит.


                1. Scf
                  24.05.2016 19:41
                  +1

                  Сложные задачи требуют много времени для решения, а зачем мучать и кандидата, и интервьювера, если все нужные выводы можно сделать на основе простой задачи, которую решат за 5 минут?


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


            1. nightshadows
              24.05.2016 20:20

              Вы много людей собеседовали? Я вот достаточно, и обычно как раз миддл и сеньор. Минимум две трети людей, прошедших даже через скайп интервтью, на очном такую задачу адекватно решить не могут. Серьёзно, об этой задаче знает подавляюще малое число миддлов даже. И если человек не понимает, почему его такое спрашивает и начинает строить сильно умного — это no hire, неумение общаться. Нам с ним не по пути (по крайней мере, в крупных и уважаемых компаниях ему врядли работать).


              1. Randl
                24.05.2016 20:42
                +4

                Я собеседования только проходил.
                Разработчики особенно толковые, могут позволить себе выбирать. И издеваясь так над интервьюером человек обычно отдает себе отчёт, что это no hire.



  1. TheTony
    24.05.2016 07:56
    +1

    Не люблю эту задачу. Зато у меня тоже есть свое «аналогичное решение» — на SQL…


  1. LifeKILLED
    24.05.2016 08:32

    Спасибо, было смешно :D


  1. 4elive8
    24.05.2016 08:33
    +14

    Интересная статья! О том как нужно ввести себя, если компания разочаровала:)


  1. artemonster
    24.05.2016 08:35
    +28

    Люди, которые не поняли комичности и сарказм истории — ВЫ ЧЕГО?!


  1. sim0nsays
    24.05.2016 08:41
    +58

    Ну да, как можно нанимать человека, который делает модель без кросс-валидации и сразу ей показывает весь датасет и оверфитит.


    1. ShashkovS
      24.05.2016 12:08
      +2

      Да и вообще: нужно было обогатить тестовые данные остатками от деления на 3 и 5 да делать решающее дерево. Работать быстрее будет! Ох уж эти любители перцептронов…


    1. SkidanovAlex
      25.05.2016 00:39
      +6

      Уоу уоу, полегче! Он тренирует на 101-1024, а тестирует на 1-100. Как можно оферфититься на примеры, которые никогда не видел?


      1. sim0nsays
        25.05.2016 01:06
        +3

        О, кто-то прочитал внимательно, круто!


  1. dmitry_ch
    24.05.2016 08:54
    +9

    За это отдельное спасибо:

    интервьюер: Отлично, отлично. Как вы относитесь к написанию кода на доске?
    я: Я только так код и пишу!

    Порадовали, отличный пост!
    А на точке
    интервьюер: [смотрит на доску с минуту]

    бедный интервьюер понял, что либо он идиот, либо его тролят )))


  1. ittakir
    24.05.2016 09:19
    +8

    Если кто не понял, эта замечательная статья — про введение в TensorFlow, а не про то, на каком языке круче писать FizzBuzz'ы.


  1. usdglander
    24.05.2016 09:19

    Странно что я не заметил у статьи тега «Юмор».


    1. PavelMSTU
      24.05.2016 09:27
      +26

      Да, он необходим.
      Так же как закадровый смех в американских ситкомах.
      А то непонятно, что пост — это сарказм


      1. usdglander
        24.05.2016 09:57
        +23

        Я оценил Ваш сарказм.
        Тег — это не указатель на эмоции, какие должен вызывать пост, а инструмент поиска и организации.


  1. voidnugget
    24.05.2016 09:24
    +2

    Выводы:


    • Либо ищут человека способного рубить леса пилочкой для ногтей, везде лепят популярные решения, без понимания их ограничений и целевых задач
    • Либо задача давалась для того что бы соискатель сказал пару ласковых интервьюеру, написал саму простую реализацию на питоне, и не пытался гнуть ель резинкой от трусов


    1. Wesha
      24.05.2016 10:12
      +3

      и не пытался гнуть ель резинкой от трусов

      Но согнул ведь! А победителей не судят.


      1. sofeykov
        24.05.2016 13:13
        +1

        Не согнул, его алгоритм ошибался.


        1. voidnugget
          24.05.2016 13:27
          -2

          Это не NP полная задача, соответственно нейросети — неуместны.


        1. Wesha
          24.05.2016 22:25

          Сеть недостаточно натренировалась, чо. :)


    1. avost
      24.05.2016 13:13
      +3

      Вывод здесь другой совершенно. А именно — ещё никогда не было так просто замутить нейронную сеть…


  1. Nepherhotep
    24.05.2016 11:07
    +10

    Отличный алгоритм. Напомнило сферический Enterprise FizzBuzz


  1. darkAlert
    24.05.2016 12:22
    -2

    Спасибо, автор! Возьму на вооружение. А то реально бесит, когда суют всякие олимпиадно-школьные задачки на интервью (не смотря на то, на какую позицию ты идешь).


  1. vstartsev
    24.05.2016 13:12

    Начало было замечательным. Но видимо интервьюер расколол любителя нейросетей, найдя у него ошибку)


  1. tron999
    24.05.2016 13:12

    Красиво затролил )


  1. forgotten
    24.05.2016 19:40
    +3

    Старая шутка про программиста, проблему и регулярные выражения обретает новое дыхание с появлением TensorFlow.


    1. forgotten
      24.05.2016 19:40
      +6

      Впрочем, до Нильса Бора, измеряющего высоту дома барометром, всё равно далеко.


      1. grossws
        24.05.2016 20:22
        -4

        Во-первых не Бор, а Паскаль. Во-вторых — метод до сих пор много где применяется (навскидку — авиация, измерение глубины пещер).


        1. mayorovp
          24.05.2016 20:32
          +3

          1. grossws
            24.05.2016 20:34

            Неправильно понял, что имел ввиду forgotten. Спасибо, это кошернее чем просто барометрическое нивелирование ,)


    1. motus
      27.05.2016 00:22

      ты вдохновил меня написать fizzbuzz на регулярных выражениях :) (см ниже)


  1. nicelight_nsk
    24.05.2016 22:02

    и все же… для не умеющих сходу решать задачу в два if(готов яростно ловить минусы, но я не кодер от природы) статья была про красивый троллинг или про ксрасивый кейс нейросети?


    1. Randl
      24.05.2016 22:22

      Про нейросети.


  1. saslanov
    24.05.2016 22:23
    +3

    Сразу вспоминается поговорка «Когда у тебя есть только молоток, все похоже на гвоздь» :)


  1. gaki
    25.05.2016 07:16

    К вопросу о затроллении интервьюера, может, кто еще не видел классический пост о функции копирования файла.


    1. Wesha
      26.05.2016 21:51

      Он мне так понравился, что я его Вам (и остальным хабравчанам) художественно перевёл


      1. gaki
        27.05.2016 13:08

        Вот еще мне нравится интервью с кандидатом на должность бизнес-аналитика о том, как передвинуть гору Фудзи: https://angryaussie.wordpress.com/2007/11/01/pointless-interview-questions/

        Ну и про дизайн велосипеда для слепых тоже отлично придумано (в самом низу, где про вентилятор):
        http://thedailywtf.com/articles/Riddle-Me-An-Interview


  1. motus
    26.05.2016 22:29
    +3

    хехе. а я вчера на регулярных выражениях написал по приколу :)

    Слабо?
    seq 0 30 | sed -r 's/^(([0369]|[147][0369]*[258 ]|([258]|[147][0369]*[147])([0369]|[258][0369]*[147])*([147]|[258][0369]*[258]))*(([147]|[258][0369]*[258])([0369]|[147 ][0369]*[258])*5|0))$/\1\tFizzBuzz/; s/^(([0369]|[147][0369]*[258]|([258]|[147][0369]*[147])([0369]|[258][0369]*[147])* ([147]|[258][0369]*[258]))*)$/\1\tFizz/; s/^([0-9]*[05])$/\1\tBuzz/'
    


    1. forgotten
      27.05.2016 00:31
      +1


    1. Scf
      27.05.2016 11:04

      Где-то ошибка — должно быть 21 Fizz, а регулярка выводит просто 21.


      sed (GNU sed) 4.2.2


      1. motus
        27.05.2016 19:17

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

        seq 0 30 | sed -r 's/^(([0369]|[147][0369]*[258]|([258]|[147][0369]*[147])([0369]|[258][0369]*[147])*([147]|[258][0369]*[258]))*(([147]|[258][0369]*[258])([0369]|[147][0369]*[258])*5|0))$/\1\tFizzBuzz/; s/^(([0369]|[147][0369]*[258]|([258]|[147][0369]*[147])([0369]|[258][0369]*[147])*([147]|[258][0369]*[258]))*)$/\1\tFizz/; s/^([0-9]*[05])$/\1\tBuzz/'
        

        это должно работать


        1. Scf
          27.05.2016 19:43

          Да, так лучше.


  1. OksikOneC
    28.05.2016 17:29

    >>Наш вход будет всего лишь двоичное кодирование числе от 1 до 100

    А вот тут проблема: а почему числа от 1 до 100 должны генериться? А как же постулат о атомарности и сохранности данных? По хорошему, эту последовательность лучше хранить в таблице базы данных. Соответственно, на доске надо бы еще привести скрипты для генерации таблицы. А для чего? Ну для SQL Server конечно, мы ж взрослы люди, в конце концов. Но мы же в 2016-ом? Поэтому нужна человеческие вьюшка. А куда ж без нее? Затем, раз мы все уж храним в базе, то автору б не мешало все его коды оформить в виде CLR модуля, написать команду компиляции оного куда? В какую-то dll, наверное. Дальше на доске скрипты разрешения CLR, подключения dll. Ну и конечно, создать пользовательские функцией с вызовом всего обвяза из ранее подключенной сборки (обучение, выводы — вот это все). И только потом, как написал коллега выше — go, nodejs и микросервисы.

    Где это всё, автор? Почему архитектуру не продумал? Почему сразу стал код писать? Что это? Вопиющая некомпетентность? Спешка? Слабость характера?

    Правильно сделали, что не взяли.

    ;)


  1. AnatoliD
    28.05.2016 17:31

    проблема в том, что на РЕАЛЬНОМ производстве, к которому интернет имеет косвенное отношение и задачи там совсем другие, проблем в том, что там такие вопросы для школьников не задают, так ценятся люди совсем другие — умеющие проектировать и реализовывать до уровня железа стенды, системы управления оборудованием и т.д.

    Собственно говоря одна из причин, почему в России не могут решить проблемы с импортозамещением или проще — осуществить новую ре — индустриализацию, состоит как раз в том, что в стране тех. специалистов (согласно статистике) только 10%, при этом специалистов занимающихся железом возможно сотые доли процента среди всех специалистов…


  1. Versusnja
    28.05.2016 17:31

    Даже такой замудреный вариант решения задачи — через перцептрон, можно было решить куда проще — в первую очередь используя используя sklearn, вместо tensorflow. Он лаконичнее решает простые задачи по машинному обучению.

    При этом сама конструкция перцептрона вызывает сомнение. На вход нет нужды подавать весь этот мусор. Это создает лишние шумы. Лучше подавать сразу остаток от деления на 3 и 5. Только 2 инпута.

    Ну и использовать softmax тоже нет нужды. Он хорош для multi-class аутпута. А это не тот случай. Правильнее было бы просто linear.

    Может тогда взяли бы на работу? А точность уж наверняка была бы 100% :)


  1. King_Lamer
    30.05.2016 17:10
    -2

    Вот еще вариант решения без использования временной переменной

    for (int i = 1; i < 101; i++)
    {
    Console.WriteLine((«fizzbuzz» + i.ToString())
    .Replace((i%3 != 0)? «fizz»: i.ToString(), "")
    .Replace((i%5 != 0)? «buzz»: i.ToString(), ""));
    }

    Мопед не мой, попросили разместить)))


  1. prijutme4ty
    02.06.2016 12:30
    +2

    Правильно не взяли, он неправильно использует инструмент. 100 слоев на такой маленькой выборке не обучить. При том, что деление на пять тривиально проверяется двухслойной сеткой, да и деление на три наверняка можно сделать при помощи двухслойной-трехслойной рекуррентной сети.