2015-06-16 38 views
-1

在一个小应用程序中,我一直使用std::vectorstd::vector<std::string>临时存储 某些数据(从非SQL数据库中提取),然后将其处理并上传到SQL数据库。不幸的是,我从中提取数据的API不一定以查询指定的顺序返回字段; 例如如果我的查询请求领域x, y, z,该数据可能会返回为y, x, z,或z, y, x,等等......显然 这是有问题的,因为如果目标SQL表的列x, y, z,然后插入数据需求 反映这一点。为了说明这个随机场排序,我写了一个小函数,它取(1)由API返回的输入数据; 和(2)代表所需列排序的std::vector<std::string>,如SQL表中定义的那样 - 并且 相应地重新排序每个子向量的元素。由于输入数据的第一行是场 名的载体,我能够把它正确有序向量与该和确定各个子矢量应该 重新排序:基于输入向量对向量进行重新排序

void fix_order(std::vector<std::vector<std::string>>& data, const std::vector<std::string>& correct) { 

    std::size_t width = data[0].size(); 
    std::vector<int> order_idx(width); 

    for (std::size_t i = 0; i < width; i++) { 
    std::string tmp(data[0].at(i)); 
    auto pos = std::find(correct.begin(), correct.end(), tmp); 
    order_idx[i] = std::distance(correct.begin(), pos); 
    } 

    for (std::size_t i = 0; i < data.size(); i++) { 
    if (!data[i].empty()) { 
     std::vector<std::string> q(width); 

     for (unsigned int j = 0; j < width; j++) { 
     int new_pos = order_idx[j]; 
     q[new_pos] = data[i].at(j); 
     } 
     std::swap(data[i], q); 
    } 
    } 
} 

在行动,如果输入的数据字段大小顺序为second, fourth, first, third,我通过指定正确的顺序矢量first, second, third, fourth,转型看起来是这样的:

Before: 
    second fourth first third 
    2nd  4th  1st  3rd 
    2nd  4th  1st  3rd 

After: 
    first second third fourth 
    1st  2nd  3rd  4th 
    1st  2nd  3rd  4th 

虽然函数产生了所需的结果,但我的循环和STL算法的混合体感觉不稳定,通常不太可读。在其他情况下,我通常可以使用std::sort以及用于非标准排序的自定义比较函数,但是我无法弄清楚如何在这里适应这种方法,其中“排序”由预定义输入确定,而不是某种类型的基于比较的逻辑。是否有一种更习惯的方式来实现这一点 - 即更好地利用STL算法(不一定是std::sort)或其他C++习惯用法?


这里是一个online demo重现的情况。

+0

我想到的第一件事:移调,排序与自定义比较,然后转回来。 –

+0

@ T.C。我同意:) – Barry

回答

2

如果转置数据,就像通过第一个元素的索引对矢量进行排序一样简单。这将是比你的解决方案速度较慢,但​​可能更容易阅读:

void fix_order(std::vector<std::vector<std::string>>& data, const std::vector<std::string>& correct) { 
    // setup index map, e.g. "first" --> 0 
    std::unordered_map<std::string, size_t> idx; 
    for (size_t i = 0; i < correct.size(); ++i) { 
     idx.insert(std::make_pair(correct[i], i)); 
    } 

    // transpose for efficient sorting 
    auto tp = transpose(std::move(data)); 

    // sort based on index map 
    std::sort(tp.begin(), tp.end(), [&](const std::vector<std::string>& lhs, const std::vector<std::string>& rhs){ 
     return idx[lhs[0]] < idx[rhs[0]]; 
    }); 

    // transpose back to get the form you wanted 
    data = transpose(std::move(tp)); 
} 

哪里transpose就是:

std::vector<std::vector<std::string>> transpose(std::vector<std::vector<std::string>>&& data) 
{ 
    std::vector<std::vector<std::string>> result(data[0].size(), 
      std::vector<std::string>(data.size())); 

    for (size_t i = 0; i < data[0].size(); ++i) { 
     for (size_t j = 0; j < data.size(); ++j) { 
      result[i][j] = std::move(data[j][i]); 
     } 
    } 

    return result; 
} 
+0

此外,考虑到用例,可能需要一个右值'数据'的破坏性转置。:) –

+0

@ T.C。固定。我想实际上可以做'交换'的权利。呃,不,我不能。 – Barry