如何按任意列动态排序数据

时间:2012-03-21 14:21:55

标签: c++

是否存在结构组合(STL,Boost等)的数据结构,允许我对内存中的数据进行排序,就像在此表中所做的那样http://en.wikipedia.org/wiki/List_of_cities_proper_by_population

我想要一个可以处理任意数量和列名称的通用解决方案。基本相似 使用sql的order by clause

获得的结果

5 个答案:

答案 0 :(得分: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

这可以通过使用向量向量来实现通用,并且比较函数可以从其环境中捕获变量:请参阅我的其他答案

答案 1 :(得分:1)

Boost.Multi-index。但是,您需要提前指定要为其构建索引的所有列。

如果你order by一个没有SQL索引的列,它只会进行线性扫描并动态构建一个排序结果集 - 你可以在C ++中做同样的事情想要通过某些专栏订购,而不是事先索引。

答案 2 :(得分:1)

好的,基于以下假设:

  • 您想按名称选择排序列
  • 你想为每一行存储类似struct的东西(使用变体类型在这里购买数量有限,但你可以去元组/类型列表路线)

你需要:

  • 某种方式将列名称与实际列
  • 相匹配
  • 某处可以挂起特定于类型的排序代码

鉴于输入和输入输出类型(未分类的容器和分类的容器)是相同的,您可以使用运行时多态性和模板的组合来完成此操作。

这是一个快速草图:

#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);
}

答案 3 :(得分:0)

我会创建一个结构的向量,每个结构模型该表的1“行”。您可以使用std :: sort和使用排序函数对不同成员进行排序,该排序函数只比较您要排序的成员。

答案 4 :(得分: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));