繁体   English   中英

根据输入向量对向量进行重新排序

[英]Reordering vector of vectors based on input vector

在一个小应用程序,我已经采用std::vectorstd::vector<std::string>以暂时存储它和上传它处理到SQL数据库之前的一些数据(从非SQL数据库拉动) 。 不幸的是,我从中提取数据的API不一定按查询指定的顺序返回字段。 例如,如果我的查询请求字段x, y, z ,则数据可能以y, x, zz, 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 ++习惯用法?


这是一个在线演示以重现这种情况。

如果转置数据,则就像按向量中第一个元素的索引对向量进行排序一样容易。 这将比您的解决方案慢,但可能更具可读性:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM