«Правильное» тестовое задание для соискателя-программиста

    Занимаясь одбором кандидатов на вакансию программиста, столкнулся с проблемой — подобрать хорошее тестовое задание. Цель — увидеть, программист ли передо мной или человек, хорошо знающий фреймворк\язык\технллогию. Поясню — программист, это человек, которые может решить нетривиальную проблему. Сделать сайт-блог, даже e-commerce сейчас является тривиальной проблемой, на это способен любой junior. Natural-born программистдумает по-другому.

    под катом образец тестового задания



    Звучит так:

    Пожалуйста, разработайте функцию\класс для «перемешивания» предложения.

    Символ | является разделителем слов-вариантов. Например:

    "{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}."

    На выходе должно получаться:

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

    Скажу сразу, что насмотрелся я много, вплоть до хардкод-массива всех возможных вариантов с выбором одного случайного, так что задание действовало. Однако «продвинутые» товарищи находят решение в интрнете и копипастят. Пользы нету от этого никому. Если кто-то когда-то выполнял интересное нетривиальное задание — буду премного благодарен. (либо в коменты либо в ЛС).
    Метки:
    Поделиться публикацией
    Комментарии 34
    • +1
      Хотел бы заметить, что задание, хорошее или не очень, должно укладываться в разумные сроки — не более, скажем, дня. Все задания, что получал (несколько штук) могу назвать интересными. Кроме одного, настолько «продвинутого» по условиям, что по оценке времени бы заняло 3 дня (ну или 1.5, если повезёт). Его не делал. Примечательно, что сразу после отправки его ко мне — мне позвонили, предупредив, что «не на 5 минут» и что это у них политика такая — давать достаточно ёмкие и близкие к практике задания и что кто-то его уже сделал и работает у них.

      (Что было — не так интересно — какое-то дерево построить в браузере, какие-то подсказки показать. От всего веяло конкретикой.)

      Наверное, это был как раз тот случай, когда хотели часть работы сделать за счёт заданий.
      • 0
        Как вариант — возьмите задачи с ACM, но обязательно переработайте.

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

        И обязательно перевести на язык рекрута, заодно дополнив условие и убрав лирику (если надо).

        Все же собеседование — это не олимпиада по спортивному программированию, и вам надо лишь узнать может ли кандидат думать как программист, а не может ли кандидат в особо сжатые сроки предложить самое лучшее, математически обоснованное решение особо не тривиальной задачи.
        • +6
          мое решение на javascript
          str = "{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}.";
          
          function change(str){
              str = str.replace(/\{([^{]+?)\}/g, function(full, match){
                  var bits = match.split('|');
                  return bits[Math.floor(Math.random(1)*bits.length)];
              });
              return str.indexOf('|') != -1 ? change(str) : str;
          }
          
          change(str);
          
          • +4
            php соответственно
            function lol($rst){
            	while( preg_match('#\{([^{}]*)\}#',$rst) ){
            		$rst = preg_replace_callback('#\{([^{}]*)\}#iUs','rst',$rst);
            	}
            	return $rst;
            }
            function rst($r){
            	$r = explode('|',$r[1]);
            	return $r[rand(0,sizeof($r)-1)];
            }
            
            echo lol("{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|
            простое} тестовое предложение {изменялось {быстро|мгновенно} случайным 
            образом|менялось каждый раз}.");
            

            • +1
              Вот только не пойму в чём нетривиальность, «блог сделать» куда сложней, если конечно у нас совпадает понимание этой фразы.
              • 0
                «блог сделать» можно по одному из туториалов, которых полно в интернете. Проекты компании немног другие, именно нетривиальные. Так что мы НЕ ищем людей для создания сайтов-блогов.
                • 0
                  Можете привести примеры таких проектов?
                  • 0
                    например, дан список доменных имен, нужно определить их ценность с точки зрения покупки\перепродажи. Учитываются различные факторы, такие как выпадение из истории (weyback records), alexa rank, Google PR и пр. Эти данные нужно собирать из различных источников, учитывая ограничения и нюансы API, либо парсить страницы напрямую.
                    • 0
                      Видимо, тут основная сложность выставить конкретную цену?
                      с технической точки зрения что сложного в получении, например, Google PR.
                      • +2
                        Если разбить эту задачу на мелкие задачи типа «ежу понятно как» то да, сложности нет. Так ведь это и есть работа хрошего программиста. Это просто пример проекта. И сложный момент здесь может быть формула, кототрая должна показывать рейтинг даже если, например, один из источников данных для конкретного домена не доступен. Например alexa не даёт результатов для mymegaporn.kz, а домен на самом деле ценный, и это нужно увидеть. Я не смогу раскрыть здесь все детали проекта.
                        • 0
                          Похоже, людей которых вы ищете, более правильно было бы назвать аналитиками, а не программистами.
                          Поскольку именно работа аналитика заключается в «выводе формул» и разбиении задачи на элементарные части.
                          • +1
                            Аналитиков придумали программисты, которые не хотели вникать в задачу :)
                          • +1
                            Согласен с Petrelevich, формулой занимаются аналитики (не без помощи людей, обладающих необходимыми знаниями и опытом).
                            А чтобы не привлекать аналитиков придумали СППР, которые позволяют автоматизировать процесс выработки решения на основе знаний и опыта. И создание нужной СППР уже задача программиста.
                            P.S. еще на википедии можно про СППР почитать, но там совсем плохое описание.
                • +1
                  Вот тоже самое, что первое пришло в голову:

                  $str =~ s!{([^{}]+)}!my @a=split(/\|/, $1); $a[int(rand(scalar(@a)))]!ge
                  while ($str =~ /[{}|]/);

                  Хотя уверен, что его можно доработать. И тоже что-то не пойму в чём сложность то.
                  • +1
                    Видимо приходит такой контингент, которого вгоняет в ступор такого рода задачи. :) Пришли попрограммировать в ворде а тут…
                • +3
                  Интересно, были ли случаи, когда для решения данной задачи кандидаты пытались использовать через какие-нибудь грамматики/трансляторы?
                  • +1
                    Мне пришлось однажды участвовать в наборе программистов в новую команду. Поделюсь опытом, может вам будет интересно.

                    Тогда мы решили воспользоваться такой структурой

                    1. логика

                    Примеры точно не могу вспомнить, но задачи были похожи на загадки с черными и белыми шариками, обезьянками и клетками и т.д. Что-то похожее недавно промелькнуло на Хабре про вопросы к претендентам в компанию Гугл. Там еще был вопрос — почему люки на улице круглые. У нас было что-то похожее, но проще.

                    2. алгоритмика

                    Здесь идут задачки, похожие на вашу. Я вспомнил свой пример — нужно было за 15 минут написать карточную игру «Дурак» для игры между человеком и компьютером.

                    Успешное прохождение такого теста подразумевало умение концентрироваться на главном, умение строить очень простые модели и реально оценивать время, ну и конечно, алгоритмику. В итоге, например, один из программистов написал на Руби программку с консольным UI. Она умела тасовать колоду, раздавать карты и простое кейс-меню для хода.

                    3. профессионализм

                    Здесь проводилось классическое интервью типа вопросы-ответы по языку программирования, фреймворкам, паттернам, тонким делам типа рефлексии и тридов

                    • 0
                      нужно было за 15 минут написать карточную игру «Дурак» для игры между человеком и компьютером.


                      В итоге, например, один из программистов написал на Руби программку с консольным UI. Она умела тасовать колоду, раздавать карты и простое кейс-меню для хода.


                      Шустро! :)
                    • 0
                      Какими знаниями должен обладать хороший программист по-Вашему?
                      • +1
                        Кроме знаний, по-моему, хороший программист должен обладать абстрактым мышлением и не думать ограничениями. Знания можно получить, а вот способность «мыслить кодом» это что-то сокральное.
                        • +5
                          Скажу вам честно, это придумали программисты, чтоб поднять себе зарплату.
                          Да и не кодом они мыслят, а логикой )
                          • 0
                            Имхо, хороший программист должен думать уже не на уровне кода, а на уровне проекта в целом. Он должен понимать что он делает, как, почему и зачем, каковы реальные цели заказчика и т.п. Хотя, возможно, у меня слишком завышенные требования.
                            • 0
                              Согласен полностью. Программист — это не леший в заколдованном лесу :) Это проводник, который знает как пройти через лес и выйти с карзиной грибов. :)))
                        • –1
                          простите,, у вас такие странные опечатки в посте и комментариях… «карзиной», «одбора»…
                          просто любопытно — это ошибки или опечатки от быстрого набора? (:
                          • +1
                            Ашипки. Я, знателе ли, решил много времени на абразавание не тратить :)
                          • +1
                            на Perl короче всех:

                            $s = '{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}.';
                            1 while $s =~ s/{([^{}]+)}/@arr = split '\|',$1; $arr[rand scalar @arr]/eg;
                            print "Result: $s\n";
                            
                            • +1
                              ну и на питоне для коллекции (:

                              import re, random

                              def repl(m):
                                while True:
                                  m, n = re.subn(r"{([^{}]*)}", lambda x: random.choice(x.group(1).split("|")), m)
                                  if (n == 0): break
                                return m

                              print repl(u"{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}.")
                              • 0
                                # -*- coding: utf-8 -*-
                                import re
                                from random import choice

                                print re.sub(r'\{(.+?)\}', lambda x: choice(x.group(1).split('|')), '{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение изменялось {быстро|мгновенно|случайным образом|менялось каждый раз}.')
                              • 0
                                Предложу такой вариант на Javascript:

                                    function Token(type, pos, value) {
                                        this.type = type;
                                        this.pos = pos;
                                        this.value = value;
                                    }
                                    Token.END_OF_LINE = 0;
                                    Token.OPERATOR = 1;
                                    Token.TEXT = 2;

                                    function Parser(text) {
                                        this._text = text;
                                        this._pos = 0;
                                        this._len = text.length;
                                    }
                                    Parser.prototype = {
                                        operators: {'{': true, '}': true, '|': true},
                                        nextToken: function() {
                                            if (this._pos >= this._len) return new Token(Token.END_OF_LINE);
                                            if (this._text[this._pos] in this.operators) {
                                                return new Token(Token.OPERATOR, this._pos, this._text[this._pos++]);
                                            }
                                            var text = '', start = this._pos;
                                            while ((this._pos < this._len) && !(this._text[this._pos] in this.operators)) {
                                                text += this._text[this._pos];
                                                this._pos++;
                                            }
                                            return new Token(Token.TEXT, start, text);
                                        },
                                        getNextToken: function() {
                                            var pos = this._pos, result = this.nextToken();
                                            this._pos = pos;
                                            return result;
                                        }
                                    };

                                    function Interpretter(text) {
                                        this._parser = new Parser(text);
                                    }
                                    Interpretter.prototype = {
                                        value: function() {
                                            var result = '', token = this._parser.getNextToken();
                                            while (token.type == Token.TEXT || (token.type == Token.OPERATOR && token.value == '{')) {
                                                token = this._parser.nextToken();
                                                if (token.type == Token.OPERATOR) {
                                                    if (token.value == '{') {
                                                        result += this.expression();
                                                    } else {
                                                        throw 'Syntax error at pos ' + token.pos;
                                                    }
                                                } else {
                                                    result += token.value;
                                                }
                                                token = this._parser.getNextToken();
                                            }
                                            return result;
                                        },
                                        expression: function() {
                                            var variants = [this.value()], token = this._parser.nextToken();
                                            while (token.value == '|') {
                                                variants.push(this.value());
                                                token = this._parser.nextToken();
                                            }
                                            if (!token.type == '}') 'Syntax error at pos ' + token.pos;
                                            return variants[Math.floor(Math.random(1) * variants.length)];
                                        }
                                    };

                                    var text = '{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}.';
                                    var interpretter = new Interpretter(text);
                                    alert(interpretter.value());


                                * This source code was highlighted with Source Code Highlighter.
                                • 0
                                  Я попробовал ООП-версию и получилось, что она по скорости от функциональной недалека.

                                • 0
                                  Отказ от копипаста хорош для проверки знаний, но в реальной работе мне кажется лучше за 20 минут найти готовый пример в интернете, чем тратить полдня на его разработку и отладку.
                                  • 0
                                    php без регекспов
                                    $p1=$p2=false;
                                    while (($p2 = strpos($str,'}'))!==false && ($p1 = strrpos(substr($str,0,$p2),'{'))!==false) {
                                        $a = explode('|', substr($str, $p1+1,$p2-$p1-1));
                                        $str = substr_replace($str, $a[rand(0,count($a)-1)], $p1, $p2+1-$p1);
                                    }
                                    
                                    • 0
                                      Оставлю здесь решение под .Net
                                      using System;
                                      using System.Collections.Generic;
                                      using System.Linq;
                                      
                                      namespace ConsoleApplication1
                                      {
                                          class Program
                                          {
                                              static void Main(string[] args)        
                                              {
                                                  string text = "{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}.";
                                                  StringRandomizerConfig config = new StringRandomizerConfig() { delim = '|', beginBrase = '{', endBrase='}'  };
                                      
                                                  var rnd = new StringRandomizer(config);
                                                  
                                                  for (int i = 0; i < 10; i++)
                                      			{
                                      			    Console.WriteLine(rnd.Rand(text));
                                      			}
                                                  Console.ReadKey();
                                              }
                                          }
                                      
                                          public struct StringRandomizerConfig
                                          {
                                              public char delim;
                                              public char beginBrase;
                                              public char endBrase;
                                          }
                                      
                                          class StringRandomizer
                                          {
                                              public StringRandomizerConfig config { get; private set; }
                                              private Random random = new Random();
                                      
                                              public StringRandomizer(StringRandomizerConfig config)
                                              {
                                                  this.config = config;
                                              }
                                      
                                              public string Rand(string text)
                                              {
                                                  var stack = new Stack<int>();
                                                  if (text.IndexOf(config.beginBrase) > -1)
                                                  {
                                                      int i = 0;
                                                      do
                                                      {
                                                          if (text[i] == config.beginBrase)
                                                          {
                                                              stack.Push(i);
                                                          }
                                                          if (text[i] == config.endBrase)
                                                          {
                                                              var firstPos = stack.Pop();
                                                              var lastPos = i;
                                      
                                                              var lenBefore = text.Length;
                                                              text = text.Replace(text.Substring(firstPos, lastPos - firstPos + 1),
                                                                  Rand(text.Substring(firstPos + 1, lastPos - firstPos - 1)));
                                                              i -= lenBefore - text.Length;
                                                          }
                                      
                                                      } while (++i < text.Length);
                                      
                                                      return text;
                                                  }
                                                  else
                                                  {
                                                      var pieces = text.Split(new[] {config.delim}, StringSplitOptions.RemoveEmptyEntries);
                                                      return pieces[random.Next(pieces.Count() - 1)];
                                                  }
                                                  
                                      
                                              }
                                      
                                          }
                                      }
                                      
                                      

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.