How to sort a vector of strings in a specific predetermined order?












8















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?










share|improve this question

























  • 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





    @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
















8















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?










share|improve this question

























  • 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





    @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














8












8








8


1






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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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













  • 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





    @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



















  • 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





    @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

















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












5 Answers
5






active

oldest

votes


















3














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





share|improve this answer
























  • In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!

    – Rosen Karadinev
    Nov 23 '18 at 11:54



















10














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





share|improve this answer

































    3














    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).






    share|improve this answer

































      1














      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.






      share|improve this answer

































        -3














        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







        share|improve this answer





















        • 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 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











        • 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











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


        }
        });














        draft saved

        draft discarded


















        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









        3














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





        share|improve this answer
























        • In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!

          – Rosen Karadinev
          Nov 23 '18 at 11:54
















        3














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





        share|improve this answer
























        • In my case there is exact 8 elements, and this solution works perfectly. Big Thanks !!

          – Rosen Karadinev
          Nov 23 '18 at 11:54














        3












        3








        3







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





        share|improve this answer













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






        share|improve this answer












        share|improve this answer



        share|improve this answer










        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



















        • 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













        10














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





        share|improve this answer






























          10














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





          share|improve this answer




























            10












            10








            10







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





            share|improve this answer















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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 23 '18 at 10:27

























            answered Nov 23 '18 at 10:12









            Davide SpataroDavide Spataro

            4,35611128




            4,35611128























                3














                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).






                share|improve this answer






























                  3














                  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).






                  share|improve this answer




























                    3












                    3








                    3







                    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).






                    share|improve this answer















                    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).







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Nov 23 '18 at 14:08

























                    answered Nov 23 '18 at 10:21









                    El ProfesorEl Profesor

                    10.8k32240




                    10.8k32240























                        1














                        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.






                        share|improve this answer






























                          1














                          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.






                          share|improve this answer




























                            1












                            1








                            1







                            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.






                            share|improve this answer















                            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.







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Nov 23 '18 at 10:25

























                            answered Nov 23 '18 at 10:18









                            palotasbpalotasb

                            2,37111420




                            2,37111420























                                -3














                                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







                                share|improve this answer





















                                • 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 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











                                • 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














                                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







                                share|improve this answer





















                                • 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 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











                                • 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








                                -3







                                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







                                share|improve this answer















                                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








                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








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











                                • 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





                                  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











                                • 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


















                                draft saved

                                draft discarded




















































                                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.




                                draft saved


                                draft discarded














                                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





















































                                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







                                Popular posts from this blog

                                To store a contact into the json file from server.js file using a class in NodeJS

                                Marschland

                                Redirect URL with Chrome Remote Debugging Android Devices