2012-03-21 3 views
1

Есть ли структура данных комбинации структур (STL, Boost и т. Д.), Которая позволила бы сортировать данные в памяти, как это делается в этой таблице здесь http://en.wikipedia.org/wiki/List_of_cities_proper_by_population

Я хотел бы получить общее решение, которое может обрабатывать количество и имена столбцов. По существу аналогичные к чему вы пользуетесь sql's order by clauseКак динамически сортировать данные по произвольным столбцам

ответ

1

Boost.Multi-index. Однако вам нужно указать все столбцы, которые вы хотите построить индексы заранее.

Если вы используете order by столбец, который не имеет индекса в SQL, он просто выполнит линейное сканирование и построит отсортированный набор результатов на лету - вы всегда можете сделать то же самое на C++, если хотите заказать по какой-то колонке вы не указали заранее.

+0

Да, SQL заказ без индекса будет делать линейное сканирование и это нормально. Я ищу гибкость, чтобы сортировать непредсказуемыми способами, даже если она может быть медленной. – user841550

2

хорошо, вам нужно будет выполнить часть работы с ногами.

Consder делает структуры или кортеж провести ряд:

struct row{ 
    unsigned rank; 
    std::string city; 
    double area; 
    //so on 
}; 

На заселить вектор или другой содержать с рядами.

std::vector<row> rows; 

Для сортировки использовать std::sort с пользовательской функцией сравнения, которые вы смотрите на определенные ценности.

std::sort(rows.begin(), rows.end(), [](const row& r1, const row& r2)->bool{ 
    return r1.area < r2.area; 
}); //sort by area 

Это может быть общим, имея вектор векторов и функцию сравнения может захватить Название переменного от его окружающей среды: видеть мой другой ответ

0

Я бы вектор структур, каждые из Struct модели 1 «строка» этой таблицы. Вы можете сортировать его разными участниками, используя std :: sort и используя функцию сортировки, которая сравнивает только участника, который вы хотите сортировать.

+0

Да, что сказал 111111. – rchilton

0

я, хотя я бы опубликовать общий ответ отдельно

Рассмотрим:

typedef std::vector<std::string> row; 
std::vector<row > table; 

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

Затем сделайте функцию сравнения, которая может работать на указанной строке

bool compare_index(std::size_t i, const row& v1, const row& v2) 
{ 
    return v1.at(i) < v2.at(i); 
} 

теперь вы можете сортировать как так

std::size_t column=2; //or which ever column 
std::sort(table.begin(), table.end(), 
      std::bind(&compare_index, col, 
       std::placeholders::_1, 
       std::placeholders::_2)); 
+0

Мне нравится эта проблема: вы ограничены хранением std :: строк. Столбцы в таблице примеров могут быть целыми числами или поплавками – user841550

+0

Это правда, но если вы хотите, чтобы это было динамично, вам нужно было сделать более сложный дизайн. Используя какой-то многопользовательский заполнитель, такой как 'boost :: variant'. Но это отдельный вопрос. (или написать свое собственное использование наследования или тому подобное). Вы можете сделать его переменной во время компиляции с помощью 'std :: tuple' вместо структуры. – 111111

1

ОК, так что на основе следующих предположений:

  • Вы хотите выбрать столбец сортировки по названию
  • лет и хотят, чтобы сохранить что-то вроде struct для каждой строки (с помощью типов вариантные покупает вам ограниченное количество, но вы могли бы пойти на кортеж/TypeList маршрут)

вам нужно:

  • каким-то образом совпадать с именем колонки фактической колонки
  • куда-нибудь повесить типа конкретного кода SORTING

Учитывая, что вход & Типы вывода (несортированный контейнер и отсортированный, соответственно) одинаковы, вы можете сделать это, используя комбинацию полиморфизма времени выполнения и шаблонов.

Вот быстрый эскиз:

#include <vector> 
#include <set> 
#include <map> 
#include <memory> 
#include <iterator> 
#include <algorithm> 

template <typename Row> class Table 
{ 
    std::vector<Row*> rows; 

    class AbstractSorter 
    { 
    protected: 
     // this doesn't have to go in AbstractSorter, 
     // but it's only used from the derived classes 
     template <typename Comp> static 
     std::vector<Row*> sort(std::vector<Row*> const &in, Comp comp) 
     { 
      std::vector<Row*> out; 
      out.reserve(in.size()); 
      // or copy and sort in place, for example 
      std::multiset<Row*, Comp> sorted(comp); 
      std::copy(in.begin(), in.end(), std::inserter(sorted, sorted.end())); 
      std::copy(sorted.begin(), sorted.end(), std::back_inserter(out)); 

      return out; 
     } 

    public: 
     virtual ~AbstractSorter() {} 
     virtual std::vector<Row*> sort(std::vector<Row*> const &) const = 0; 
    }; 

    typedef std::unique_ptr<AbstractSorter> SortPtr; 
    typedef std::map<std::string, SortPtr> SortMap; 
    static SortMap sorters; 

    template <typename ColType> 
    class ConcreteSorter: public AbstractSorter 
    { 
     ColType Row::*col; 

    public: 
     ConcreteSorter(ColType Row::*member) : col(member) {} 
     virtual std::vector<Row*> sort(std::vector<Row*> const &in) const 
     { 
      // assuming you have C++11 lambdas, otherwise you'll need to 
      // write a comparator too 
      return AbstractSorter::sort(
       in, 
       [&col](Row *a, Row *b){ return (a->*col) < (b->*col); } 
       ); 
     } 
    }; 

public: 
    template <typename ColType> 
    static void bindSortableColumn(char const *name, ColType Row::*member) 
    { 
     sorters.insert(typename SortMap::value_type(
       std::string(name), 
       SortPtr(new ConcreteSorter<ColType>(member)) 
       )); 
    } 

    // error handling left as an exercise for the reader 
    std::vector<Row*> sortBy(std::string const &name) const 
    { 
     return sorters[name]->sort(rows); 
    } 
}; 

#define SORTABLE_COLUMN(ROW, COL) \ 
    Table<ROW>::bindSortableColumn(#COL, &ROW::COL); 

template <typename Row> typename Table<Row>::SortMap Table<Row>::sorters; 

// now to define your own row type  
struct MyRow 
{ 
    int id; 
    std::string name; 
    double salary; 
}; 

// and the tedious bit: setting up the sorter objects for your columns 
// (you could automate this further by using a tuple instead of a regular 
// struct for MyRow) 
void init_columns() 
{ 
    SORTABLE_COLUMN(MyRow, id); 
    SORTABLE_COLUMN(MyRow, name); 
    SORTABLE_COLUMN(MyRow, salary); 
} 
Смежные вопросы