На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Поиск по заданному полю большой структуры , чистый Си ( С89-90 )
    Всем хай!

    Допустим, есть сущность "Автомобиль", состоящая из 28 полей ( в примере приведу лишь первые 4 шт. ):
    ExpandedWrap disabled
      typedef struct Car
      {
          char* mark;         // марка
          char* country;          // страна-производитель
          double price;           // цена в млн.руб.
          unsigned int max_speed;     // максимальная скорость
          ...
      } Car;


    И вот должна быть возможность поиска по ЛЮБОМУ полю авто, т е по марке, по цене и т.п. Напомню, что всего 28 полей.
    А почему бы просто не реализовать 28 "похожих" функций, типа такого:
    ExpandedWrap disabled
      void Search_mark( ... );
      void Search_country( ... );
      void Search_price( ... );
      ...


    Это ведь приемлемый вариант для языка Си ( стандарта С89-90 ), верно? :)

    С др.стороны можно все засунуть в ОДНУ поисковую функцию и там поставить switch. На мой взгляд это архинегибко. Гораздо удобнее иметь 28 маленьких функций, чем одну огромную ( неповоротливую функцию-годзиллу ) с выбором.

    спс. за внимание

    Добавлено
    кстати, еще ведь надо данные сортировать также по ЛЮБОМУ полю
    думаю, что это еще +28 функций), но сортировка будет индексной, чтобы не сбивать первоначальное расположение данных
    в одну общую функцию засовывать все возможные сортировки - вроде абсолютно плохая идея

    итого на поиски и на сортировки потребуется 56 функций...
    или все-таки все совсем по-другому можно реализовать?)
      FasterHarder, ты пытаешься изобрести СУБД? Все эти проблемы давно решены в них.

      Добавлено
      В плюсах это можно сделать на шаблонах без дублирования кода. В чистом Си тут можно что-нибудь с макросами придумать, хотя будет не очень красиво и потенциально опасно. Еще можно сделать обертку на уровне смещений полей в структуре, но т.к. поля разные, то и функций все равно придется делать несколько (потом можно обернуть во что-то более высокоуровневое).
      Сообщение отредактировано: shm -
        Цитата FasterHarder @
        или все-таки все совсем по-другому можно реализовать?)

        Как правильно заметил shm - лучше использовать готовые решения. И время сэкономишь, и кому-то иному твой код будет гораздо понятнее. В качестве инструмента, если не ориентироваться на внешние СУБД, можно использовать SQLite. А если нужны скоростные операции, SQLite может размещать свои данные в памяти. Плюс ко всему получаешь полноценный язык запросов SQL.
          Шо, опять автомобили? В прошлой теме уже же объяснили, что ты решаешь задачу, правильный метод решения которой это "взять БД". Да хоть sqlite бери, который с полпинка где угодно заведётся.
          Ну и постановка странная достаточно. "Поиск по цене" - это что, например? Практически всегда интересует диапазон цен, а значит у тебя у функций принципиально разные сигнатуры будут, а не просто втупую "выполняем поиск по полю функцией, принимающей значение этого поля".
            bsearch(), qsort(). Они принимают указатель на функцию сравнения, которую можно написать как требуется
              На самом деле тебе не надо иметь 28 функций сравнения, можно обойтись только теми, что работают с разными типами данных и дополнительно передавать поле, по которому структуры сравниваются. Функции вполне можно сделать универсальными. На Плюсах можно было б закаррировать в лямбде, на Cях посложнее. Но что-то типа (не тестировал!):
              ExpandedWrap disabled
                const void *search(const void *key, const void *data, size_t count, size_t size,
                                   int (*comp)(const void*, const void*, size_t), size_t offset)
                {
                  const unsigned char* it, *end = (const unsigned char*)data + size*count;
                 
                  for (it = data; it < end; it += size)
                    if (comp(it, key, offset) != 0) break;
                  return it < end ? it : NULL;
                }
                 
                typedef struct Car
                {
                  char        *mark;            // марка
                  char        *country;         // страна-производитель
                  double       price;           // цена в млн.руб.
                  unsigned int max_speed;       // максимальная скорость
                  /* ...*/
                } Car;
                 
                int comp_double(const void *left, const void* right, size_t offs)
                {
                  const double *l = (const double*)((const unsigned char*)left + offs),
                               *r = (const double*)right;
                  return *l == *r;
                }
                 
                int comp_unsigned_int(const void *left, const void* right, size_t offs)
                {
                  const unsigned int *l = (const unsigned int*)((const unsigned char*)left + offs),
                                     *r = (const unsigned int*)right;
                  return *l == *r;
                }
                 
                int comp_char_ptr(const void *left, const void* right, size_t offs)
                {
                  const char *l = (const char*)((const unsigned char*)left + offs),
                             *r = (const char*)right;
                  return strcmp(l, r) == 0;
                }
                 
                Car array[ARRAY_SIZE];
                 
                void f(void)
                {
                  double   dummy1 = 200000.0/1000000;
                  unsigned dummy2 = 250;
                 
                  const Car *myCar        = search("Корыто", array, ARRAY_SIZE, sizeof (*array), comp_char_ptr,    offsetof(Car, mark));
                  const Car *myFavorSeller= search("Россия", array, ARRAY_SIZE, sizeof (*array), comp_char_ptr,    offsetof(Car, country));
                  const Car *myMountlyPay = search(&dummy1,  array, ARRAY_SIZE, sizeof (*array), comp_double,      offsetof(Car, price));
                  const Car *myFavorSpeed = search(&dummy2,  array, ARRAY_SIZE, sizeof (*array), comp_unsigned_int,offsetof(Car, max_speed));
                  /* ...*/
                }
                Qraizer, поклон за этот подход!
                Нечто подобное рассматривает Стив М. в разделе "Пример гибкого формата сообщений", где рассматриваются бакены :) Там же он доказывает бессильность ООП в таких случаях.
                Т е здесь ты применяешь лучшие мировые техники программирования. Ну а кто ж сомневался, что ты сишный ( + С++ ) демон!

                Qraizer, но с др.стороны ведь так удобно иметь маленькие функции, которые легко модифицировать. Например, надо искать двигатели не заданного объема, а заданных 2-3 объемов - все поменять в одном месте легко. Или по диапазону что-нибудь искать и т.п.

                всем спс, а перед Qraizer снимаю шляпу ( в общем-то как и всегда ) )) В мире НЕ существует задачи на Си, которой Qraizer не сломает хребет, хотя ... :whistle:
                  Цитата FasterHarder @
                  Там же он доказывает бессильность ООП в таких случаях.
                  Он прав лишь в том, что ООП далеко не везде вообще нужен. Так-то сравни с той же реализацией на Плюсах:
                  ExpandedWrap disabled
                    typedef struct Car
                    {
                      std::string  mark;            // марка
                      std::string  country;         // страна-производитель
                      double       price;           // цена в млн.руб.
                      unsigned int max_speed;       // максимальная скорость
                      /* ...*/
                    } Car;
                     
                    std::array<Car, ARRAY_SIZE> autoPark;
                     
                    void f(void)
                    {
                      using namespace std::literals;
                     
                      auto myCar        = std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return val.mark   == "Корыто"s; });
                      auto myFavorSeller= std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return val.country== "Россия"s; });
                      auto myMountlyPay = std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return val.price     == 0.2; });
                      auto myFavorSpeed = std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return val.max_speed == 250; });
                      /* ...*/
                    }
                  Лямбды формально можно сохранять в отдельных переменных и не писать многократно то тут, то там одно и то же. К примеру, вон те четыре строчки можно свести к универсальному:
                  ExpandedWrap disabled
                    auto comp(const auto &it, const auto& key, auto member) { return it.*member == key; }
                     
                    void g(void)
                    {
                      using namespace std::literals;
                     
                      auto myCar        = std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return comp(val, "Корыто"s, &Car::mark);    });
                      auto myFavorSeller= std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return comp(val, "Россия"s, &Car::country); });
                      auto myMountlyPay = std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return comp(val,       0.2, &Car::price);     });
                      auto myFavorSpeed = std::find_if(autoPark.begin(), autoPark.end(), [](const auto &val){ return comp(val,       250, &Car::max_speed); });
                      /* ...*/
                    }
                  просто в таком простом случае в этом нет особого смысла. Для более сложных компараторов (тут это comp) каррирование одного из его параметров позволит обойтись его единственным экземпляром, а частные лямбды останутся лёгкими.

                  Добавлено
                  P.S. Формально тут никакого каррирования нет. Это я на случай, если сюда зайдёт какой-нибудь D_KEY ;) Каррирование в точном смысле этого термина означает немного другое и гораздо более обобщённое понятие.
                    Цитата Qraizer @
                    P.S. Формально тут никакого каррирования нет. Это я на случай, если сюда зайдёт какой-нибудь D_KEY Каррирование в точном смысле этого термина означает немного другое и гораздо более обобщённое понятие.
                    P.P.S. Вот так больше будет похоже на каррирование:
                    ExpandedWrap disabled
                      auto check= [](auto member, const auto& key) { return [=](const auto &it) { return comp(it, key, member); }; };
                       
                      void f(void)
                      {
                        using namespace std::literals;
                       
                        auto myCar        = std::find_if(autoPark.begin(), autoPark.end(), check(&Car::mark,   "Корыто"s));
                        auto myFavorSeller= std::find_if(autoPark.begin(), autoPark.end(), check(&Car::country,"Россия"s));
                        auto myMountlyPay = std::find_if(autoPark.begin(), autoPark.end(), check(&Car::price,     0.2));
                        auto myFavorSpeed = std::find_if(autoPark.begin(), autoPark.end(), check(&Car::max_speed, 250));
                        /* ...*/
                      }
                    Идея в сокращении количества передаваемых параметров путём фиксации некоторых из них и указании их значений отдельно. Но всё равно это не совсем полноценное каррирование.
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0337 ]   [ 16 queries used ]   [ Generated: 26.04.24, 12:14 GMT ]