问题:我需要以确切的特定顺序对字符串向量进行排序。假设我们有一个常数向量或具有精确顺序的数组:
vector<string> correctOrder = {"Item3", "Item1", "Item5", "Item4", "Item2"};
接下来,我们有一个动态的传入向量,该向量将具有相同的Item,但它们可能是混合的并且数量较少。
vector<string> incommingVector = {"Item1", "Item5", "Item3"};
因此,我需要按照第一个向量incomming
的顺序对correctOrder
向量进行排序,结果必须为:
vector<string> sortedVector = {"Item3", "Item1", "Item5"};
我认为正确的顺序可能以不同的方式表示,但无法弄清楚。 有人可以帮我吗?
答案 0 :(得分:10)
如果默认比较还不够(字典比较),那么您可以做的最简单的事情就是为sort函数提供一个lambda,告诉它哪个字符串在前。
您可以将correctorder
向量中的字符串作为键,并将它们在排序数组中的对应位置作为值的unordered_map<string,int>
。
cmp
函数将只比较您在incommingVector
中提供的键的值。
unordered_map<string, int> my_map;
for(int i = 0 ; i < correctorder.size() ; i++)
my_map[correctorder[i]]=i;
auto cmp =[&my_map](const string& s, const string& s1){
return my_map[s] < my_map[s1];
}
sort(incommingVector.begin(), incommingVector.end() , cmp);
答案 1 :(得分:3)
您可以利用std::unordered_map<std::string, int>
的优势,即用于在恒定时间内将字符串映射为整数的哈希表。您可以使用它来找出给定的字符串在correctOrder
中的向量O(1)
中所占的位置,以便可以在恒定时间内比较向量incomming
中的两个字符串。
考虑以下功能sort_incomming_vector()
:
#include <unordered_map>
using Vector = std::vector<std::string>;
void sort_incomming_vector(const Vector& correctOrder /*N*/, Vector& incomming /*M*/)
{
std::unordered_map<std::string, int> order;
// populate the order hash table in O(N) time
for (size_t i = 0; i < correctOrder.size(); ++i)
order[correctOrder[i]] = i;
// sort "incomming" in O(M*log M) time
std::sort(incomming.begin(), incomming.end(),
[&order](const auto& a, const auto& b) { // sorting criterion
return order[a] < order[b];
}
);
}
哈希表order
将映射为整数,该结果整数将被传递给排序算法{{3}的lambda(即排序标准)使用},以比较向量incomming
中的一对字符串,以便排序算法可以相应地对它们进行置换。
如果correctOder
包含N
个元素,并且incomming
包含M
个元素,则可以在O(N)
时间和{{1 }}可以在incomming
时间内排序。因此,整个算法将在O(M*log M)
时间运行。
如果O(N + M*log M)
比N
大得多,则此解决方案是最佳的,因为主导项将是M
,即N
〜O(N + M*log M)
。
答案 2 :(得分:3)
您可以创建自己的函子,以按照以下代码说明的模板矢量顺序对矢量进行排序:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct MyComparator
{
//static const int x = 9;
const std::vector<std::string> correctOrder{"Item1", "Item2", "Item3", "Item4", "Item5"};
bool operator() (const std::string& first,const std::string& second )
{
auto firstitr = std::find(correctOrder.begin(),correctOrder.end(),first);
auto seconditr = std::find(correctOrder.begin(),correctOrder.end(),second);
return firstitr < seconditr;
}
};
void printVector(const std::vector<std::string>& input)
{
for(const auto&elem:input)
{
std::cout<<elem<<" , ";
}
std::cout<<std::endl;
}
int main()
{
std::vector<string> incomingVector = {"Item3", "Item5", "Item1"};
std::cout<<"vector before sort... "<<std::endl;
printVector(incomingVector);
std::sort(incomingVector.begin(),incomingVector.end(),MyComparator());
std::cout<<"vector after sort...."<<std::endl;
printVector(incomingVector);
return 0;
}
答案 3 :(得分:1)
您需要创建一个比较函数,该函数返回正确的顺序并将其传递给std::sort
。为此,您可以编写一个可重用的函数,该函数返回一个lambda,该lambda将对尝试std::find
的两个元素进行比较的结果进行比较。 std::find
返回迭代器,您可以将其与<
运算符进行比较。
#include <algorithm>
std::vector<std::string> correctOrder = {"Item1", "Item2", "Item3", "Item4", "Item5"};
// Could be just std::string correctOrder[], or std::array<...> etc.
// Returns a sorter that orders elements based on the order given by the iterator pair
// (so it supports not just std::vector<string> but other containers too.
template <typename ReferenceIter>
auto ordered_sorter(ReferenceIter ref_begin, ReferenceIter ref_end) {
// Note: you can build an std::unordered_map<ReferenceIter::value_type, std::size_t> to
// be more efficient and compare map.find(left)->second with
// map.find(right)->second (after you make sure the find does not return a
// one-past-the-end iterator.
return [&](const auto& left, const auto& right) {
return std::find(ref_begin, ref_end, left) < std::find(ref_begin, ref_end, right);
};
}
int main() {
using namespace std;
vector<string> v{"Item3", "Item5", "Item1"};
// Pass the ordered_sorter to std::sort
std::sort(v.begin(), v.end(), ordered_sorter(std::begin(correctOrder), std::end(correctOrder)));
for (const auto& s : v)
std::cout << s << ", "; // "Item1, Item3, Item5, "
}
请注意,对于大量元素,此答案的效率较低,但比使用std::unordered_map<std::string, int>
进行查找的解决方案更简单,但是对于少量元素,线性搜索可能会更快。如果性能很重要,请进行基准测试。
答案 4 :(得分:-3)
编辑:如果您不希望使用默认比较,则需要将自定义比较方法作为第三个参数传递,如链接参考中存在的示例所示。
使用std::sort
,您已完成:
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
#include <string> // std::string
using namespace std;
int main () {
vector<string> incommingVector = {"Item3", "Item5", "Item1"};
// using default comparison (operator <):
std::sort (incommingVector.begin(), incommingVector.end());
// print out content:
std::cout << "incommingVector contains:";
for (std::vector<string>::iterator it=incommingVector.begin(); it!=incommingVector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
输出:
incommingVector包含:Item1 Item3 Item5