2015-06-16 90 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