Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.237.15.145] |
|
Сообщ.
#1
,
|
|
|
Всем хай!
Допустим, есть сущность "Автомобиль", состоящая из 28 полей ( в примере приведу лишь первые 4 шт. ): typedef struct Car { char* mark; // марка char* country; // страна-производитель double price; // цена в млн.руб. unsigned int max_speed; // максимальная скорость ... } Car; И вот должна быть возможность поиска по ЛЮБОМУ полю авто, т е по марке, по цене и т.п. Напомню, что всего 28 полей. А почему бы просто не реализовать 28 "похожих" функций, типа такого: void Search_mark( ... ); void Search_country( ... ); void Search_price( ... ); ... Это ведь приемлемый вариант для языка Си ( стандарта С89-90 ), верно? С др.стороны можно все засунуть в ОДНУ поисковую функцию и там поставить switch. На мой взгляд это архинегибко. Гораздо удобнее иметь 28 маленьких функций, чем одну огромную ( неповоротливую функцию-годзиллу ) с выбором. спс. за внимание Добавлено кстати, еще ведь надо данные сортировать также по ЛЮБОМУ полю думаю, что это еще +28 функций), но сортировка будет индексной, чтобы не сбивать первоначальное расположение данных в одну общую функцию засовывать все возможные сортировки - вроде абсолютно плохая идея итого на поиски и на сортировки потребуется 56 функций... или все-таки все совсем по-другому можно реализовать?) |
Сообщ.
#2
,
|
|
|
FasterHarder, ты пытаешься изобрести СУБД? Все эти проблемы давно решены в них.
Добавлено В плюсах это можно сделать на шаблонах без дублирования кода. В чистом Си тут можно что-нибудь с макросами придумать, хотя будет не очень красиво и потенциально опасно. Еще можно сделать обертку на уровне смещений полей в структуре, но т.к. поля разные, то и функций все равно придется делать несколько (потом можно обернуть во что-то более высокоуровневое). |
Сообщ.
#3
,
|
|
|
Цитата FasterHarder @ или все-таки все совсем по-другому можно реализовать?) Как правильно заметил shm - лучше использовать готовые решения. И время сэкономишь, и кому-то иному твой код будет гораздо понятнее. В качестве инструмента, если не ориентироваться на внешние СУБД, можно использовать SQLite. А если нужны скоростные операции, SQLite может размещать свои данные в памяти. Плюс ко всему получаешь полноценный язык запросов SQL. |
Сообщ.
#4
,
|
|
|
Шо, опять автомобили? В прошлой теме уже же объяснили, что ты решаешь задачу, правильный метод решения которой это "взять БД". Да хоть sqlite бери, который с полпинка где угодно заведётся.
Ну и постановка странная достаточно. "Поиск по цене" - это что, например? Практически всегда интересует диапазон цен, а значит у тебя у функций принципиально разные сигнатуры будут, а не просто втупую "выполняем поиск по полю функцией, принимающей значение этого поля". |
Сообщ.
#5
,
|
|
|
bsearch(), qsort(). Они принимают указатель на функцию сравнения, которую можно написать как требуется
|
Сообщ.
#6
,
|
|
|
На самом деле тебе не надо иметь 28 функций сравнения, можно обойтись только теми, что работают с разными типами данных и дополнительно передавать поле, по которому структуры сравниваются. Функции вполне можно сделать универсальными. На Плюсах можно было б закаррировать в лямбде, на Cях посложнее. Но что-то типа (не тестировал!):
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)); /* ...*/ } |
Сообщ.
#7
,
|
|
|
Qraizer, поклон за этот подход!
Нечто подобное рассматривает Стив М. в разделе "Пример гибкого формата сообщений", где рассматриваются бакены Там же он доказывает бессильность ООП в таких случаях. Т е здесь ты применяешь лучшие мировые техники программирования. Ну а кто ж сомневался, что ты сишный ( + С++ ) демон! Qraizer, но с др.стороны ведь так удобно иметь маленькие функции, которые легко модифицировать. Например, надо искать двигатели не заданного объема, а заданных 2-3 объемов - все поменять в одном месте легко. Или по диапазону что-нибудь искать и т.п. всем спс, а перед Qraizer снимаю шляпу ( в общем-то как и всегда ) )) В мире НЕ существует задачи на Си, которой Qraizer не сломает хребет, хотя ... |
Сообщ.
#8
,
|
|
|
Цитата FasterHarder @ Он прав лишь в том, что ООП далеко не везде вообще нужен. Так-то сравни с той же реализацией на Плюсах:Там же он доказывает бессильность ООП в таких случаях. 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; }); /* ...*/ } 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); }); /* ...*/ } Добавлено P.S. Формально тут никакого каррирования нет. Это я на случай, если сюда зайдёт какой-нибудь D_KEY Каррирование в точном смысле этого термина означает немного другое и гораздо более обобщённое понятие. |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ P.P.S. Вот так больше будет похоже на каррирование:P.S. Формально тут никакого каррирования нет. Это я на случай, если сюда зайдёт какой-нибудь D_KEY Каррирование в точном смысле этого термина означает немного другое и гораздо более обобщённое понятие. 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)); /* ...*/ } |