How to sort a vector of strings in a specific predetermined order?
The problem: I need to sort a vector of strings in exact specific order. Let say we have a constant vector or a array with the exact order:
vector<string> correctOrder = {"Item3", "Item1", "Item5", "Item4", "Item2"};
Next, we have a dynamic incoming vector which will have same Items, but they maybe mixed and less in number.
vector<string> incommingVector = {"Item1", "Item5", "Item3"};
So I need to sort the incomming
vector with the order like the first vector, correctOrder
, and the result must be:
vector<string> sortedVector = {"Item3", "Item1", "Item5"};
I think the correct order may be represented in a different way, but can't figure out.
Can someone help me please?
c++ string algorithm sorting vector
add a comment |
The problem: I need to sort a vector of strings in exact specific order. Let say we have a constant vector or a array with the exact order:
vector<string> correctOrder = {"Item3", "Item1", "Item5", "Item4", "Item2"};
Next, we have a dynamic incoming vector which will have same Items, but they maybe mixed and less in number.
vector<string> incommingVector = {"Item1", "Item5", "Item3"};
So I need to sort the incomming
vector with the order like the first vector, correctOrder
, and the result must be:
vector<string> sortedVector = {"Item3", "Item1", "Item5"};
I think the correct order may be represented in a different way, but can't figure out.
Can someone help me please?
c++ string algorithm sorting vector
Usingstd::sort
for the actual sorting is a good start. I also suggest reading about lambda expressions to provide a custom comparison function that you pass tostd::sort
to use.
– Some programmer dude
Nov 23 '18 at 10:09
2
@gsamaras Maybe. Or maybe the OP wants to use the elements in the vectorcorrectOrder
to get the relative positions of the elements? I don't know, it's not really clear from the question.
– Some programmer dude
Nov 23 '18 at 10:14
1
This that is correct gsamaras. I need to sort relative to first vector.
– Rosen Karadinev
Nov 23 '18 at 10:37
I see that all of the answers are offline. Is there a more efficient online algorithm?
– Andrew Scott
Nov 23 '18 at 11:10
While all the answers tell you how you can solve in O(N * M log M), you can achieve this in O(log N * M log M) by using heaps, since they only take log N time for insertion. Note that it is not possible to lookup the values in the middle because then you would have to spend M time.
– Andrew Scott
Nov 23 '18 at 11:22
add a comment |
The problem: I need to sort a vector of strings in exact specific order. Let say we have a constant vector or a array with the exact order:
vector<string> correctOrder = {"Item3", "Item1", "Item5", "Item4", "Item2"};
Next, we have a dynamic incoming vector which will have same Items, but they maybe mixed and less in number.
vector<string> incommingVector = {"Item1", "Item5", "Item3"};
So I need to sort the incomming
vector with the order like the first vector, correctOrder
, and the result must be:
vector<string> sortedVector = {"Item3", "Item1", "Item5"};
I think the correct order may be represented in a different way, but can't figure out.
Can someone help me please?
c++ string algorithm sorting vector
The problem: I need to sort a vector of strings in exact specific order. Let say we have a constant vector or a array with the exact order:
vector<string> correctOrder = {"Item3", "Item1", "Item5", "Item4", "Item2"};
Next, we have a dynamic incoming vector which will have same Items, but they maybe mixed and less in number.
vector<string> incommingVector = {"Item1", "Item5", "Item3"};
So I need to sort the incomming
vector with the order like the first vector, correctOrder
, and the result must be:
vector<string> sortedVector = {"Item3", "Item1", "Item5"};
I think the correct order may be represented in a different way, but can't figure out.
Can someone help me please?
c++ string algorithm sorting vector
c++ string algorithm sorting vector
edited Nov 23 '18 at 17:45
El Profesor
10.8k32240
10.8k32240
asked Nov 23 '18 at 10:05
Rosen KaradinevRosen Karadinev
1069
1069
Usingstd::sort
for the actual sorting is a good start. I also suggest reading about lambda expressions to provide a custom comparison function that you pass tostd::sort
to use.
– Some programmer dude
Nov 23 '18 at 10:09
2
@gsamaras Maybe. Or maybe the OP wants to use the elements in the vectorcorrectOrder
to get the relative positions of the elements? I don't know, it's not really clear from the question.
– Some programmer dude
Nov 23 '18 at 10:14
1
This that is correct gsamaras. I need to sort relative to first vector.
– Rosen Karadinev
Nov 23 '18 at 10:37
I see that all of the answers are offline. Is there a more efficient online algorithm?
– Andrew Scott
Nov 23 '18 at 11:10
While all the answers tell you how you can solve in O(N * M log M), you can achieve this in O(log N * M log M) by using heaps, since they only take log N time for insertion. Note that it is not possible to lookup the values in the middle because then you would have to spend M time.
– Andrew Scott
Nov 23 '18 at 11:22
add a comment |
Usingstd::sort
for the actual sorting is a good start. I also suggest reading about lambda expressions to provide a custom comparison function that you pass tostd::sort
to use.
– Some programmer dude
Nov 23 '18 at 10:09
2
@gsamaras Maybe. Or maybe the OP wants to use the elements in the vectorcorrectOrder
to get the relative positions of the elements? I don't know, it's not really clear from the question.
– Some programmer dude
Nov 23 '18 at 10:14
1
This that is correct gsamaras. I need to sort relative to first vector.
– Rosen Karadinev
Nov 23 '18 at 10:37
I see that all of the answers are offline. Is there a more efficient online algorithm?
– Andrew Scott
Nov 23 '18 at 11:10
While all the answers tell you how you can solve in O(N * M log M), you can achieve this in O(log N * M log M) by using heaps, since they only take log N time for insertion. Note that it is not possible to lookup the values in the middle because then you would have to spend M time.
– Andrew Scott
Nov 23 '18 at 11:22
Using
std::sort
for the actual sorting is a good start. I also suggest reading about lambda expressions to provide a custom comparison function that you pass to std::sort
to use.– Some programmer dude
Nov 23 '18 at 10:09
Using
std::sort
for the actual sorting is a good start. I also suggest reading about lambda expressions to provide a custom comparison function that you pass to std::sort
to use.– Some programmer dude
Nov 23 '18 at 10:09
2
2
@gsamaras Maybe. Or maybe the OP wants to use the elements in the vector
correctOrder
to get the relative positions of the elements? I don't know, it's not really clear from the question.– Some programmer dude
Nov 23 '18 at 10:14
@gsamaras Maybe. Or maybe the OP wants to use the elements in the vector
correctOrder
to get the relative positions of the elements? I don't know, it's not really clear from the question.– Some programmer dude
Nov 23 '18 at 10:14
1
1
This that is correct gsamaras. I need to sort relative to first vector.
– Rosen Karadinev
Nov 23 '18 at 10:37
This that is correct gsamaras. I need to sort relative to first vector.
– Rosen Karadinev
Nov 23 '18 at 10:37
I see that all of the answers are offline. Is there a more efficient online algorithm?
– Andrew Scott
Nov 23 '18 at 11:10
I see that all of the answers are offline. Is there a more efficient online algorithm?
– Andrew Scott
Nov 23 '18 at 11:10
While all the answers tell you how you can solve in O(N * M log M), you can achieve this in O(log N * M log M) by using heaps, since they only take log N time for insertion. Note that it is not possible to lookup the values in the middle because then you would have to spend M time.
– Andrew Scott
Nov 23 '18 at 11:22
While all the answers tell you how you can solve in O(N * M log M), you can achieve this in O(log N * M log M) by using heaps, since they only take log N time for insertion. Note that it is not possible to lookup the values in the middle because then you would have to spend M time.
– Andrew Scott
Nov 23 '18 at 11:22
add a comment |
5 Answers
5
active
oldest
votes
You can create your own functor to sort your vector in template vector order as explained by below code :
#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;
}
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
add a comment |
If the default comparison is not enough (lexicographic comparison) then the simplest thing you can do is to provide the sort function with a lambda that tells it which string come first.
You can have a unordered_map<string,int>
with the strings in your correctorder
vector as keys and their corresponding position in the sorted array as values.
The cmp
function will simply compare the values of the keys you provide in your 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);
add a comment |
You can take advantage of std::unordered_map<std::string, int>
, i.e., a hash table for mapping a string into an integer in constant time. You can use it for finding out the position that a given string occupies in your vector correctOrder
in O(1)
, so that you can compare two strings that are in the vector incomming
in constant time.
Consider the following function 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];
}
);
}
The hash table order
maps the strings into integers, and this resulting integer is used by the lambda (i.e., the sorting criterion) passed to the sorting algorithm, std::sort
, to compare a pair strings in the vector incomming
, so that the sorting algorithm can permute them accordingly.
If correctOder
contains N
elements, and incomming
contains M
elements, then the hash table can be initialised in O(N)
time, and incomming
can be sorted in O(M*log M)
time. Therefore, the whole algorithm will run in O(N + M*log M)
time.
If N
is much larger than M
, this solution is optimal, since the dominant term will be N
, i.e., O(N + M*log M)
~ O(N)
.
add a comment |
You need to create a comparison function that returns the correct ordering and pass that to std::sort
. To do that, you can write a reusable function that returns a lambda that compares the result of trying to std::find
the two elements being compared. std::find
returns iterators, and you can compare those with the <
operator.
#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, "
}
Note that this answer less efficient with a large number of elements, but more simpler than the solutions using an std::unordered_map<std::string, int>
for lookup, but a linear search is probably faster for small number of elements. Do your benchmarking if performance matters.
add a comment |
Edit: If you don't want the default comparison to be used, then you need to pass as a third parameter your custom compare method, as shown in the example that exists in the linked reference.
Use std::sort
and you are done:
#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;
}
Output:
incommingVector contains: Item1 Item3 Item5
3
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter ofstd::sort()
. Please see the reference I linked to my answer for more.
– gsamaras
Nov 23 '18 at 10:14
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53444532%2fhow-to-sort-a-vector-of-strings-in-a-specific-predetermined-order%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can create your own functor to sort your vector in template vector order as explained by below code :
#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;
}
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
add a comment |
You can create your own functor to sort your vector in template vector order as explained by below code :
#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;
}
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
add a comment |
You can create your own functor to sort your vector in template vector order as explained by below code :
#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;
}
You can create your own functor to sort your vector in template vector order as explained by below code :
#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;
}
answered Nov 23 '18 at 10:45
KapilKapil
885718
885718
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
add a comment |
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!
– Rosen Karadinev
Nov 23 '18 at 11:54
add a comment |
If the default comparison is not enough (lexicographic comparison) then the simplest thing you can do is to provide the sort function with a lambda that tells it which string come first.
You can have a unordered_map<string,int>
with the strings in your correctorder
vector as keys and their corresponding position in the sorted array as values.
The cmp
function will simply compare the values of the keys you provide in your 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);
add a comment |
If the default comparison is not enough (lexicographic comparison) then the simplest thing you can do is to provide the sort function with a lambda that tells it which string come first.
You can have a unordered_map<string,int>
with the strings in your correctorder
vector as keys and their corresponding position in the sorted array as values.
The cmp
function will simply compare the values of the keys you provide in your 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);
add a comment |
If the default comparison is not enough (lexicographic comparison) then the simplest thing you can do is to provide the sort function with a lambda that tells it which string come first.
You can have a unordered_map<string,int>
with the strings in your correctorder
vector as keys and their corresponding position in the sorted array as values.
The cmp
function will simply compare the values of the keys you provide in your 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);
If the default comparison is not enough (lexicographic comparison) then the simplest thing you can do is to provide the sort function with a lambda that tells it which string come first.
You can have a unordered_map<string,int>
with the strings in your correctorder
vector as keys and their corresponding position in the sorted array as values.
The cmp
function will simply compare the values of the keys you provide in your 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);
edited Nov 23 '18 at 10:27
answered Nov 23 '18 at 10:12
Davide SpataroDavide Spataro
4,35611128
4,35611128
add a comment |
add a comment |
You can take advantage of std::unordered_map<std::string, int>
, i.e., a hash table for mapping a string into an integer in constant time. You can use it for finding out the position that a given string occupies in your vector correctOrder
in O(1)
, so that you can compare two strings that are in the vector incomming
in constant time.
Consider the following function 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];
}
);
}
The hash table order
maps the strings into integers, and this resulting integer is used by the lambda (i.e., the sorting criterion) passed to the sorting algorithm, std::sort
, to compare a pair strings in the vector incomming
, so that the sorting algorithm can permute them accordingly.
If correctOder
contains N
elements, and incomming
contains M
elements, then the hash table can be initialised in O(N)
time, and incomming
can be sorted in O(M*log M)
time. Therefore, the whole algorithm will run in O(N + M*log M)
time.
If N
is much larger than M
, this solution is optimal, since the dominant term will be N
, i.e., O(N + M*log M)
~ O(N)
.
add a comment |
You can take advantage of std::unordered_map<std::string, int>
, i.e., a hash table for mapping a string into an integer in constant time. You can use it for finding out the position that a given string occupies in your vector correctOrder
in O(1)
, so that you can compare two strings that are in the vector incomming
in constant time.
Consider the following function 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];
}
);
}
The hash table order
maps the strings into integers, and this resulting integer is used by the lambda (i.e., the sorting criterion) passed to the sorting algorithm, std::sort
, to compare a pair strings in the vector incomming
, so that the sorting algorithm can permute them accordingly.
If correctOder
contains N
elements, and incomming
contains M
elements, then the hash table can be initialised in O(N)
time, and incomming
can be sorted in O(M*log M)
time. Therefore, the whole algorithm will run in O(N + M*log M)
time.
If N
is much larger than M
, this solution is optimal, since the dominant term will be N
, i.e., O(N + M*log M)
~ O(N)
.
add a comment |
You can take advantage of std::unordered_map<std::string, int>
, i.e., a hash table for mapping a string into an integer in constant time. You can use it for finding out the position that a given string occupies in your vector correctOrder
in O(1)
, so that you can compare two strings that are in the vector incomming
in constant time.
Consider the following function 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];
}
);
}
The hash table order
maps the strings into integers, and this resulting integer is used by the lambda (i.e., the sorting criterion) passed to the sorting algorithm, std::sort
, to compare a pair strings in the vector incomming
, so that the sorting algorithm can permute them accordingly.
If correctOder
contains N
elements, and incomming
contains M
elements, then the hash table can be initialised in O(N)
time, and incomming
can be sorted in O(M*log M)
time. Therefore, the whole algorithm will run in O(N + M*log M)
time.
If N
is much larger than M
, this solution is optimal, since the dominant term will be N
, i.e., O(N + M*log M)
~ O(N)
.
You can take advantage of std::unordered_map<std::string, int>
, i.e., a hash table for mapping a string into an integer in constant time. You can use it for finding out the position that a given string occupies in your vector correctOrder
in O(1)
, so that you can compare two strings that are in the vector incomming
in constant time.
Consider the following function 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];
}
);
}
The hash table order
maps the strings into integers, and this resulting integer is used by the lambda (i.e., the sorting criterion) passed to the sorting algorithm, std::sort
, to compare a pair strings in the vector incomming
, so that the sorting algorithm can permute them accordingly.
If correctOder
contains N
elements, and incomming
contains M
elements, then the hash table can be initialised in O(N)
time, and incomming
can be sorted in O(M*log M)
time. Therefore, the whole algorithm will run in O(N + M*log M)
time.
If N
is much larger than M
, this solution is optimal, since the dominant term will be N
, i.e., O(N + M*log M)
~ O(N)
.
edited Nov 23 '18 at 14:08
answered Nov 23 '18 at 10:21
El ProfesorEl Profesor
10.8k32240
10.8k32240
add a comment |
add a comment |
You need to create a comparison function that returns the correct ordering and pass that to std::sort
. To do that, you can write a reusable function that returns a lambda that compares the result of trying to std::find
the two elements being compared. std::find
returns iterators, and you can compare those with the <
operator.
#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, "
}
Note that this answer less efficient with a large number of elements, but more simpler than the solutions using an std::unordered_map<std::string, int>
for lookup, but a linear search is probably faster for small number of elements. Do your benchmarking if performance matters.
add a comment |
You need to create a comparison function that returns the correct ordering and pass that to std::sort
. To do that, you can write a reusable function that returns a lambda that compares the result of trying to std::find
the two elements being compared. std::find
returns iterators, and you can compare those with the <
operator.
#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, "
}
Note that this answer less efficient with a large number of elements, but more simpler than the solutions using an std::unordered_map<std::string, int>
for lookup, but a linear search is probably faster for small number of elements. Do your benchmarking if performance matters.
add a comment |
You need to create a comparison function that returns the correct ordering and pass that to std::sort
. To do that, you can write a reusable function that returns a lambda that compares the result of trying to std::find
the two elements being compared. std::find
returns iterators, and you can compare those with the <
operator.
#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, "
}
Note that this answer less efficient with a large number of elements, but more simpler than the solutions using an std::unordered_map<std::string, int>
for lookup, but a linear search is probably faster for small number of elements. Do your benchmarking if performance matters.
You need to create a comparison function that returns the correct ordering and pass that to std::sort
. To do that, you can write a reusable function that returns a lambda that compares the result of trying to std::find
the two elements being compared. std::find
returns iterators, and you can compare those with the <
operator.
#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, "
}
Note that this answer less efficient with a large number of elements, but more simpler than the solutions using an std::unordered_map<std::string, int>
for lookup, but a linear search is probably faster for small number of elements. Do your benchmarking if performance matters.
edited Nov 23 '18 at 10:25
answered Nov 23 '18 at 10:18
palotasbpalotasb
2,37111420
2,37111420
add a comment |
add a comment |
Edit: If you don't want the default comparison to be used, then you need to pass as a third parameter your custom compare method, as shown in the example that exists in the linked reference.
Use std::sort
and you are done:
#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;
}
Output:
incommingVector contains: Item1 Item3 Item5
3
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter ofstd::sort()
. Please see the reference I linked to my answer for more.
– gsamaras
Nov 23 '18 at 10:14
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
add a comment |
Edit: If you don't want the default comparison to be used, then you need to pass as a third parameter your custom compare method, as shown in the example that exists in the linked reference.
Use std::sort
and you are done:
#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;
}
Output:
incommingVector contains: Item1 Item3 Item5
3
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter ofstd::sort()
. Please see the reference I linked to my answer for more.
– gsamaras
Nov 23 '18 at 10:14
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
add a comment |
Edit: If you don't want the default comparison to be used, then you need to pass as a third parameter your custom compare method, as shown in the example that exists in the linked reference.
Use std::sort
and you are done:
#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;
}
Output:
incommingVector contains: Item1 Item3 Item5
Edit: If you don't want the default comparison to be used, then you need to pass as a third parameter your custom compare method, as shown in the example that exists in the linked reference.
Use std::sort
and you are done:
#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;
}
Output:
incommingVector contains: Item1 Item3 Item5
edited Nov 23 '18 at 10:35
answered Nov 23 '18 at 10:10
gsamarasgsamaras
51.4k24101188
51.4k24101188
3
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter ofstd::sort()
. Please see the reference I linked to my answer for more.
– gsamaras
Nov 23 '18 at 10:14
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
add a comment |
3
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter ofstd::sort()
. Please see the reference I linked to my answer for more.
– gsamaras
Nov 23 '18 at 10:14
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
3
3
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
Okey But lets say the correct order is {"Item4", "Item1", "Item3", "Item2", "Item5"}; would be work like this?
– Rosen Karadinev
Nov 23 '18 at 10:13
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter of
std::sort()
. Please see the reference I linked to my answer for more.– gsamaras
Nov 23 '18 at 10:14
@RosenKaradinev for that you would need to use a custom compare function, that you would pass as the third parameter of
std::sort()
. Please see the reference I linked to my answer for more.– gsamaras
Nov 23 '18 at 10:14
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
I think you misread the question and OP didnt use the best example (for the example in the question a simple sort does it, but not in the general case)
– user463035818
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Not an answer to the question
– NiVeR
Nov 23 '18 at 10:17
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
Thanks to @RosenKaradinev I now understand the question!
– Neil Gatenby
Nov 23 '18 at 10:32
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53444532%2fhow-to-sort-a-vector-of-strings-in-a-specific-predetermined-order%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Using
std::sort
for the actual sorting is a good start. I also suggest reading about lambda expressions to provide a custom comparison function that you pass tostd::sort
to use.– Some programmer dude
Nov 23 '18 at 10:09
2
@gsamaras Maybe. Or maybe the OP wants to use the elements in the vector
correctOrder
to get the relative positions of the elements? I don't know, it's not really clear from the question.– Some programmer dude
Nov 23 '18 at 10:14
1
This that is correct gsamaras. I need to sort relative to first vector.
– Rosen Karadinev
Nov 23 '18 at 10:37
I see that all of the answers are offline. Is there a more efficient online algorithm?
– Andrew Scott
Nov 23 '18 at 11:10
While all the answers tell you how you can solve in O(N * M log M), you can achieve this in O(log N * M log M) by using heaps, since they only take log N time for insertion. Note that it is not possible to lookup the values in the middle because then you would have to spend M time.
– Andrew Scott
Nov 23 '18 at 11:22