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

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

  1. ensane

    ensane Гость

    Репутация:
    0
    Вот задачка, которая была предложена на собеседовании при приеме на работу штатного юнита на должность "Программист 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 Гость

    Репутация:
    0
    на 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 Гость

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

    Kmet Well-Known Member
    Java Team

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

    lazybiz Well-Known Member
    C\C++ Team

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

    Rififi Гость

    Репутация:
    0
    ensane

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

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

    ensane Гость

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

    Kmet Well-Known Member
    Java Team

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

    ensane Гость

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

    hosm * so what *

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

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

    lazybiz Well-Known Member
    C\C++ Team

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

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

    ensane Гость

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

    hosm * so what *

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

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

    Akupaka А че я?.. О.о

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

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

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

    А OKEN права во всем.
     
Загрузка...
Похожие Темы - Задача собеседования для
  1. petiablack
    Ответов:
    0
    Просмотров:
    22
  2. disub
    Ответов:
    1
    Просмотров:
    127
  3. Kazua
    Ответов:
    1
    Просмотров:
    121
  4. Rina
    Ответов:
    0
    Просмотров:
    81
  5. School_Information

    Решите Задача

    Ответов:
    2
    Просмотров:
    219

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