1. Мегаконкурс в апреле "Приведи друзей на codeby". Дарим деньги, подписку на журнал хакер и выдаем статус "Paid Access". Подробнее ...

    Скрыть объявление

Задача: C собеседования для приема на работу

Тема в разделе "Свободное общение", создана пользователем ensane, 17 дек 2010.

Наш партнер Genesis Hackspace
  1. ensane

    ensane Гость

    Вот задачка, которая была предложена на собеседовании при приеме на работу штатного юнита на должность "Программист C++". Из 6 соискателей, только 4 смогли ее решить. И у троих она работала не вполне правильно. То ли Брест совсем скуден на таланты, то ли все смотались в Минск строить парк высоких технологий, то ли что... Предлагаю вам. Чисто из интереса голову поломать ;)
    Дано: есть файл, содержащий некую конфигурацию. Файл состоит из строк вида:
    1. name=value
    Где name - имя параметра, а value - его значение. Значение может быть 4 типов:
    1.1: целое число. Считаем параметр целым, если его значение записано целым числом (например val=1)
    1.2: вещественное с плавающей запятой. К вещественным относим все числа, которые не попали в п 1.1 ( val=1.0 )
    1.3: строка. Считаем параметр строкой, если его значение заключено в двойные кавычки "". Под значением понимаем ВСЕ, ЧТО ВНУТРИ КАВЫЧЕК, КРОМЕ САМИХ КАВЫЧЕК (val="string")
    1.4: ссылка на другой параметр. Значение начинается с символа &, за которым следует имя другого параметра. (val2=&val1. )
    2. Символы пробела и табуляции игнорируются, за исключением случаем, когда они входят в значение строкового параметра (val=" string").
    3. Если строка начинается с символа (с учетом пункта 2) "#", то она считается комментарием и игнорируется.
    4. В одной строке не может быть двух пар "имя=значение"
    Надо:
    Написать класс, который будет реализовывать следующее:
    1. Считывать файл конфигурации с диска в память
    2. Проверять на наличие ошибок и в случае наличия оных выдавать список строк с указанием на ошибки
    3. Реализовывать следующие методы:
    3.1. isSet(const std::string param_name) - имеется ли параметр с указанным именем?
    3.2. getType(const std::string param_name) - получить тип параметра. (TP_INT, TP_DBL, TP_STR), для ссылки - тип параметра, на который ссылаемся
    3.3. getValueAsInt(const std::string param_name), getValueAsDouble, getValueAsStr - получить значение, для ссылки - значение параметра, на который ссылаемся.
    3.4. При реализации п3.3. по возможности предусмотреть конвертацию типов.

    Условия выполнения - дома. Полученный код должен был быть представлен в двух файлах *.h и *.cpp
    Проверялся на MSVS 8.0
     
  2. Rififi

    Rififi Гость

    на C++ что-то вроде того...
    нет первых двух пунктов, ибо очень лень возиться с файловыми потоками, поэтому считывание данных происходит из строки и обработка ошибок максимально упрощена.

    .h
    Код (C++):
    #pragma once

    #include <map>
    #include <iostream>
    #include <sstream>
    #include <locale>

    #include <boost/spirit/home/qi.hpp>
    #include <boost/spirit/home/support/multi_pass.hpp>
    #include <boost/spirit/home/phoenix.hpp>

    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    namespace phx = boost::phoenix;

    #include <boost/variant.hpp>
    #include <boost/fusion/adapted.hpp>
    #include <boost/lexical_cast.hpp>

    #include <boost/mpl/at.hpp>
    #include <boost/mpl/map.hpp>
    namespace mpl = boost::mpl;

    typedef boost::make_recursive_variant<int, float, std::string, boost::recursive_variant_*>::type data_type;
    typedef std::pair<std::string, data_type> key_value_type;

    typedef std::vector<std::pair<std::string, std::string> > alias_list;
    typedef std::map<std::string, data_type> configuration_map;

    enum DataType
    {
    TP_INT,
    TP_FLOAT,
    TP_STRING
    };

    namespace detail {

    typedef mpl::map<
    mpl::pair<int, mpl::int_<TP_INT> >,
    mpl::pair<float, mpl::int_<TP_FLOAT> >,
    mpl::pair<std::string, mpl::int_<TP_STRING> >
    > DataTypeMapper;

    }

    class Conf
    {
    public:
    Conf(const std::string& source);

    class TypeCaster
    {
    public:
    TypeCaster(const data_type& val) : val_(val)
    {
    }

    template <typename T>
    T As() const
    {
    return boost::apply_visitor(TypeCasterVis<T>(), val_);
    }

    DataType Type() const
    {
    return boost::apply_visitor(TypeFinderVis(), val_);
    }

    protected:
    template <typename T>
    struct TypeCasterVis : public boost::static_visitor<T>
    {
    template <typename U>
    T operator()(const U& u) const
    {
    return cast(u, boost::is_convertible<U, T>());
    }

    template <>
    T operator()(data_type* const& val) const
    {
    if (val == NULL)
    return T();

    return boost::apply_visitor(*this, *val);
    }

    template <typename U>
    static T cast(U u, mpl::true_)
    {              
    return static_cast<T>(u);
    }

    template <typename U>
    static T cast(U u, mpl::false_)
    {
    return boost::lexical_cast<T>(u);
    }
    };

    struct TypeFinderVis : public boost::static_visitor<DataType>
    {
    template <typename T>
    DataType operator()(const T&) const
    {
    using detail::DataTypeMapper;
    return (DataType) typename mpl::at<DataTypeMapper, T>::type::value;
    }

    template <>
    DataType operator()(data_type* const& val) const
    {
    return boost::apply_visitor(*this, *val);
    }
    };

    protected:
    const data_type& val_;
    };

    const TypeCaster operator[](const std::string& name) const
    {
    const configuration_map::const_iterator found = conf_.find(name);
    if (found == conf_.end())
    throw std::runtime_error("Variable is not found.");

    return TypeCaster(found->second);
    }

    size_t size() const
    {
    return conf_.size();
    }

    protected:
    template <typename Range, typename Arg>
    void parse_impl(const Range& rng, Arg& arg, alias_list& aliases);

    public:
    configuration_map conf_;
    };
    .cpp
    Код (C++):
    #include "parse_config.h"

    #include <math.h>
    #include <assert.h>

    template <typename InputIterator, typename Skipper>
    struct grammar : public qi::grammar<InputIterator, configuration_map(), Skipper>
    {
    grammar(alias_list& aliases) : grammar::base_type(start_)
    {
    unesc_char.add
    ("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n')
    ("\\r", '\r')("\\t", '\t')("\\v", '\v')
    ("\\\\", '\\')("\\\'", '\'')("\\\"", '\"')
    ;

    start_ = +pair_;
    pair_ %= key_ >> '=' >> value_(phx::at_c<0>(qi::_val)) >> qi::eol;
    key_ = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
    value_ = string_ | float_ | qi::int_ | ref_(qi::_r1);
    ref_ = '&' >> key_ [
    qi::_val = nullptr,
    phx::push_back(phx::ref(aliases), phx::construct<alias_list::value_type>(qi::_r1, qi::_1))
    ];
    string_ = '\"' >> *(unesc_char | "\\x" >> qi::hex | (qi::print - '\"')) >> '\"';
    }

    #pragma region Rules

    qi::rule<InputIterator, configuration_map(), Skipper> start_;
    qi::rule<InputIterator, key_value_type(), Skipper> pair_;

    qi::rule<InputIterator, std::string()> key_;
    qi::rule<InputIterator, data_type(const std::string&)> value_;
    qi::rule<InputIterator, data_type*(const std::string&)> ref_;

    qi::rule<InputIterator, std::string()> string_;

    template <typename T>
    struct strict_real_policies : qi::real_policies<T>
    {
    static bool const expect_dot = true;
    };

    template <typename T, template <typename> class policy>
    struct real_parser
    {
    typedef qi::real_parser<T, policy<T> > type;
    };

    typename real_parser<float, strict_real_policies>::type float_;

    qi::symbols<const char, const char> unesc_char;

    #pragma endregion
    };

    Conf::Conf(const std::string& source)
    {
    alias_list aliases;
    parse_impl(source, conf_, aliases);

    for (alias_list::const_iterator it = aliases.begin(); it != aliases.end(); ++it)
    {
    const configuration_map::iterator origin = conf_.find(it->second);
    if (origin != conf_.end())
    conf_[it->first] = &origin->second;
    }
    }

    template <typename Range, typename Arg>
    void Conf::parse_impl(const Range& rng, Arg& arg, alias_list& aliases)
    {
    typedef typename boost::range_iterator<const Range>::type InputIterator;

    InputIterator begin = boost::const_begin(rng);
    const InputIterator end = boost::const_end(rng);

    typedef qi::rule<InputIterator> skipper_type;
    const skipper_type skipper = qi::char_(" \t") | '#' >> *(qi::char_ - qi::eol) >> qi::eol;

    const grammar<InputIterator, skipper_type> g(aliases);
    const bool ok = qi::phrase_parse(begin, end, g, skipper, arg);
    if (!(ok && begin == end))
    throw std::runtime_error("Parsing failed.");
    }
    Использование:
    Код (C++):
        const std::string source =
    "#comment \n"
    "name_int = 100\n"
    "name_float = 258.23\n"
    "name_str = \"123 #some \\\"string\\\" 456.0\"\n"
    "str_alias = &name_str\n"
    "int_alias = &name_int\n"
    "none = &zzz\n"
    "# more comment ...\n"
    "int_alias2 = &int_alias\n"
    "# more comment ...\n"
    ;

    const Conf conf(source);

    assert(conf.size() == 7);

    assert(conf["name_int"].Type() == TP_INT);
    assert(conf["name_float"].Type() == TP_FLOAT);
    assert(conf["name_str"].Type() == TP_STRING);

    assert(conf["int_alias"].Type() == TP_INT);
    assert(conf["int_alias2"].Type() == TP_INT);   

    assert(conf["name_int"].As<int>() == 100);
    assert(conf["name_int"].As<std::string>() == std::string("100"));
    assert(conf["name_float"].As<long>() == 258);
    assert(fabs(conf["name_float"].As<double>() - 258.23) < 0.001);

    assert(conf["name_str"].As<std::string>() == std::string("123 #some \"string\" 456.0"));
    assert(conf["str_alias"].As<std::string>() == std::string("123 #some \"string\" 456.0"));

    assert(conf["none"].As<int>() == 0);
    assert(conf["none"].As<std::string>() == std::string());

    assert(conf["name_int"].As<float>() == 100.0f);
    assert(conf["name_float"].As<float>() == 258.23f);

    assert(conf["int_alias"].As<int>() == 100);
    assert(conf["int_alias2"].As<float>() == 100.0f);
     
  3. ensane

    ensane Гость

    Rififi
    Фэйл. Даже не начало собираться, выругавшись на отсутствие boost'а. После такого я предлагал соискателю переделать и придти на другой день.
     
  4. Kmet

    Kmet Well-Known Member
    Java Team

    Регистрация:
    25 май 2006
    Сообщения:
    1.032
    Симпатии:
    6
    ensane
    не смогли собрать приложение с бустом в зависимостях?! ай яй яй. Фейл ваш. Ограничений на использование сторонних библиотек в задание нету. Наличие билд скрипта тоже не прописано.
     
  5. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Kmet
    А boost входит в стандартный набор MSVS 8.0 ?
     
  6. Rififi

    Rififi Гость

    ensane

    Даже не начало собираться, выругавшись на отсутствие boost'а.

    В предложение перед словом boost нужно добавить местоимение "какого-то". Тогда будет совсем шикарно.
     
  7. ensane

    ensane Гость

    Rififi,
    Kmet
    Есть более 18 либ, почти реализующих функционал, требуемый задачей. (18 - это то, что я нашел в гугле за несколько минут поисков). Может, сразу подключим их и не будем париться? Вся задачка решится за 10 минут и сотню строчек кода, а то и меньше. Так что абсолютный фэйл.
     
  8. Kmet

    Kmet Well-Known Member
    Java Team

    Регистрация:
    25 май 2006
    Сообщения:
    1.032
    Симпатии:
    6
    А вот не надо передергивать. Rififi выбрал правильный инструмент. Парсить без использование граматик и генераторов парсеров... Это надо сильно себя не любить. Имхо, это вообще тест на адекватность. Вот Rififi его прошел, а вы,ensane, нет.
     
  9. ensane

    ensane Гость

    Kmet
    Еще раз намекаю: если бы это была задача на выбор инструмента для разработки, то и в этом случае использование boost'а было бы фэйлом. Потому как есть более подходящие для данной задачи инструменты.
    Кстати, это второй фэйл. Первый фэйл - не были заданы необходимые уточняющие вопросы перед началом решения. На собеседовании мы за это сразу снижали баллы.
     
  10. hosm

    hosm * so what *

    Регистрация:
    18 май 2009
    Сообщения:
    2.445
    Симпатии:
    8
    хм, а к чему это? А разве не вы отвечаете за точную постановку задачи перед тем, как предоставить ее?
    Почему вы считаете, что умолчав или не описав четко требования к решению, вы вправе осуждать других, что они сделали так, как им было удобней?
     
  11. European

    Регистрация:
    4 сен 2006
    Сообщения:
    2.566
    Симпатии:
    1
    ensane клонит к тому, что идеальный кандидат (с его точки зрения) должен был сначала уточнить требования, а только потом кидаться на реализацию. Т.е. сначала думать, а потом делать. Кстати, это очень распространённая практика на собеседованиях: заставить кандидата думать
     
  12. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Kmet
    Если он все сделал правильно, то почему он не реализовал это?

    Это вот как он его прошел позвольте узнать. Условия задания для кого даны?
     
  13. ensane

    ensane Гость

    OKEN
    Потому что это не олимпиадная задачка и не задача на зачет по предмету.
    European
    В точку.
     
  14. hosm

    hosm * so what *

    Регистрация:
    18 май 2009
    Сообщения:
    2.445
    Симпатии:
    8
    ensane Задача выбора, уточнения и согласования требований - это задача аналитика, технического консультанта и/или архитектора системы. И вот как раз программист не обязательно должен играть постоянно в проекте роль аналитика и проводить кучу времени на телефоне/в скайпе/по мейлу, уточняя каждый раз требования у заказчика. И ваша задача как заказчика тестового задания - предоставить всю требуемую для решения задачи информацию. Если это не оговорено в требованиях заказчика, то программист вправе выбирать средства и методы решения на свое усмотрение, и качество выбора уже зависит от квалификации программиста.
    У вас настолько простые проекты, что нет никакого распределения ролей в проекте - каждый программист отвечает только за один проект, где он сам себе руководитель, технический консультант, аналитик, архитектор, кодировщик, тестировщик, технический писатель и внедренец в одном лице? Просто у нас есть такое разделение, и человек, занимающийся уточнением требований с заказчиком - это либо бизнес-аналитик, либо программист-аналитик или конструктор системы, и не всякому пришедшему на работу программисту это стоит позволять делать. Если написание тех.документации и переговоры с заказчиком - это было оговорено в требованиях к вакансии - да, пожалуйста, претензии снимаются...
    European И 6 человек, пришедших на собеседование, должны были долго и нудно выяснять у автора темы практически одно и то же, что они поленились описать в первоначальной постановке? Рациональное использование времени, да, нефиг делать =)
     
  15. European

    Регистрация:
    4 сен 2006
    Сообщения:
    2.566
    Симпатии:
    1
    Из 6-ти только 1-2 уточнят требования, а вот все остальные, с большОй долей вероятности - изобретатели велосипедов. То что ты говоришь все очень правильно, но программист должен уметь работать и без аналитика/консультанта/архитектора. А то вечером перед релизом он тебе такой велосипед с квадратными колесами в репозиторий зальёт, что будешь полночи откатывать, а потом перед заказчиками оправдываться
     
  16. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.363
    Симпатии:
    2
    А по-моему эта задача никак не отображает умение думать. Разве только знание синтаксиса языка и умение использовать его конструкции.

    Так, а с чего вы там у себя решили, что эти "необходимые уточняющие вопросы" являются абсолютно необходимыми для решения поставленной задачи?

    А чего ж тогда оценка кандидатов идет по этому принципу? "Мы не смогли открыть Вашу программу, поэтому Ваша работа не защитана."

    А OKEN права во всем.
     
Загрузка...
Похожие Темы - Задача собеседования для
  1. School_Information
    Ответов:
    2
    Просмотров:
    91
  2. KhNarg
    Ответов:
    2
    Просмотров:
    163
  3. Янчик
    Ответов:
    0
    Просмотров:
    617
  4. TrishaRay
    Ответов:
    1
    Просмотров:
    862
  5. elzim
    Ответов:
    0
    Просмотров:
    1.003

Поделиться этой страницей