-2

I have a vector<string> containing several words that are based on user input. They are are all stored in the vector using a variable named container. I need to arrange the words in the string into an unconventional QWERTY-order, or in other words I need them to be sorted based on the string string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM"; So a sample run would look like this

Enter a word: apple Enter a word: pear Enter a word: peach

Words sorted in QWERTY order: pear peach apple

I'm currently only able to store these character strings, and since they are not alphabetical I cannot use the character values in if-statements,

I was given a hint to use sort-selection or insertion to compare my vector-string to the QWERTY-sequence, but I'm unable to find any examples in my Textbook or online on how to apply this to my code. Any help would be greatly appreciated, thank you for your time.

laura
  • 15
  • 5
  • you don't need any sort-selection. It's a very simple lookup table to find the character corresponding with the qwerty string. Also, please pick a language, C or C++. The C++ solution is two lines, maybe one. – PaulMcKenzie Feb 22 '17 at 00:56
  • Sorry, I am not used to navigating this website and I think I entered tags incorrectly. I don't understand what you mean by lookup table, is there a good reference I can look at? – laura Feb 22 '17 at 00:59
  • Think outside the box. What if `myword` is "PEAR". What would be `sequence[myword[0]]`, `sequence[myword[1]]`, `sequence[myword[2]]`, , `sequence[myword[3]]`? So in your sort, you're comparing the values of sequence array using the characters of "PEAR" as a lookup. – PaulMcKenzie Feb 22 '17 at 01:09
  • their numerical values would be 10,3,11,4, right? – laura Feb 22 '17 at 01:15
  • Remember that arrays are 0-based, so that would be 9, 2, 10, 3. – PaulMcKenzie Feb 22 '17 at 01:19
  • Oh, I see! However I don't understand how the solution is only two lines.. – laura Feb 22 '17 at 01:33
  • You have n words entered. That is a `vector`. I won't count that. Then you have `std::sort` on the vector of strings strings. The sort criteria calls a function to determine if one string is less than the other, OK, 5 lines. Without using the STL sort algorithm, and lambda functions, expect to write the "beginner level" 30 lines of code. – PaulMcKenzie Feb 22 '17 at 03:12
  • Laura, the hint your were given to use a [selection sort](https://en.wikipedia.org/wiki/Selection_sort) or an [insertion sort](https://en.wikipedia.org/wiki/Insertion_sort) leads me to guess this may be a programming class assignment? A solution based on `std::sort` is absolutely the right answer from a programming efficiency point of view - never write code you don't need to write! But it may not be the right answer in this case if your instructor is trying to give you the experience of writing a sort implementation for yourself. Just something to think about. – Frank Boyne Feb 22 '17 at 05:40
  • Yes, it's a programming class assignment. I don't know the instructor's intentions, but the hint was supposed to make it easier on us, however it is not required to follow the hints. – laura Feb 22 '17 at 05:56
  • Even for a programming class, using `std::sort` for this problem shows that you have mastered the most important programming skill: writing just what's needed, and reusing what's reusable. In particular, the unique challenge here is how you order two strings. Given that, `std::sort` can order N strings. – MSalters Feb 22 '17 at 09:24
  • @MSalters I hear what you are saying but gaining the ability to write what's needed involves learning to write code. Implementing an insertion sort or selection sort might be a waste of effort for an experienced programmer but it's still a useful programming exercise that can give valuable experience to someone learning to code. – Frank Boyne Feb 23 '17 at 23:34

5 Answers5

0

One option is to replace every character by the corresponding one from your special alphabet. Then do a sort and change back.

For example:

we -> bc, er -> cd
koalo
  • 2,113
  • 20
  • 31
  • Assign every character some kind of value? How could I apply the sort function to that? – laura Feb 22 '17 at 00:57
  • I understand what you mean, but wouldn't I need a loop for every letter of the alphabet? If I assign them the values of different letters wouldn't it print incorrectly? – laura Feb 22 '17 at 01:06
0

Just use std::string::find to find index of a symbol and compare them:

bool sequenceLess( const std::string &s1, const std::string &s2 )
{
    static const std::string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
    for( size_t i = 0; i < s1.length(); ++i ) {
        if( i >= s2.length() ) return false;
        auto idx1 = sequence.find( ::toupper( s1[i] ) );
        auto idx2 = sequence.find( ::toupper( s2[i] ) );
        if( idx1 == idx2 ) continue;
        return idx1 < idx2;
    }
    return true;
}

another version is to convert a string to vector of indexes and compare them:

std::vector<size_t> convert( const std::string &s )
{
    static const std::string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
    std::vector<size_t> r( s.size() );
    std::transform( s.begin(), s.end(), r.begin(), [sequence]( char c ) {
         return sequence.find( ::toupper( c ) );
     } );
    return r;
}

// now comparison is obvious
bool sequenceLess( const std::string &s1, const std::string &s2 )
{
    return convert( s1 ) < convert( s2 );
}

this solution is inefficient, but for learning purpose should be ok.

Slava
  • 43,454
  • 1
  • 47
  • 90
0

You can try customize sort. Please refer to this link Sorting a vector of custom objects

Below is my code sample for your case, but I dint handle for lower case letters.

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

struct mySort{
     inline bool operator() (const string& s1, const string& s2)
    {
        bool isSort = false;

        if(s1.length() < s2.length()){
            return true;
        }else if(s1.length() > s2.length()){
            return false;
        }

        //s1.length() == s1.length()
        string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
        int index1 = 0 , index2 = 0;
        for(int i = 0 ; i < s1.length() ; i++){

            for(int j = 0 ; j < sequence.length() ; j++){
                if(s1[i] == sequence[j]){
                    index1 = j;

                }
                if(s2[i] == sequence[j]){
                    index2 = j;
                }
            }

            if(index1 < index2){return true;}
        }

        return false;
    }
};

int main(){


    vector<string> myVector;
    myVector.push_back("APPLE");
    myVector.push_back("PEAR");
    myVector.push_back("PEACH");
    sort(myVector.begin(), myVector.end(), mySort());
    for(int i = 0 ; i < myVector.size() ; i++){
        cout<<myVector[i]<<endl;
    }

    return 1;
}

Here is the result,

enter image description here

PS : Maybe I miss some conditions, but just share with you, how to apply the customize sort.

Community
  • 1
  • 1
Anson Tan
  • 1,256
  • 2
  • 13
  • 34
  • This is the style of code I am used to seeing, so I think I can understand it a little better. I am a bit confused though, as in this case the words 'subdue' and 'superior' do not properly sort into qwerty order, – laura Feb 22 '17 at 02:00
  • Because I set the priority of length is higher than sequence, subdue is shorter than superior so, it will come first. [PS: Make sure you key in as capital letter] – Anson Tan Feb 22 '17 at 02:09
  • BTW, this is just a sample code to show you how it works. You can design your own sorting condition inside the struct, hope my sharing is helpful. – Anson Tan Feb 22 '17 at 02:11
  • Sorry, I wasn't clear in my post! The length of the word is irrelevant, I'm only trying to sort based on letters sequencing (Q->W->E, etc.), so that first boolean is not necessary? But yes, your example was extremely helpful! thank you very much for your time. – laura Feb 22 '17 at 02:14
  • Then the comparison of length is not necessary, but you need to find out the shortest length. int shortestLen = s1.length(); if(s1.length()>s2.length()){shortestLen = s2.length()}. So in the loop, use for(int i = 0 ; i < shortestLen ; i++){ – Anson Tan Feb 22 '17 at 02:51
0

You can overload < operator for strings and then use c++ function sort() located in <algorithm> I don't quite understand how do you exactly want to sort strings with that rule, so it's up to you to encode the comparison of two strings, and that would be it.

Barsik the Cat
  • 363
  • 1
  • 2
  • 10
0

Edit: Added the lookup table and corrected the tests in getless.

Here is another solution using std::sort and a function that tests each string and returns true if one string is less than the other in QWERTY order:

#include <algorithm>
#include <string>
#include <vector>
#include <cctype>
#include <iostream>

typedef std::vector<std::string> StringVect;
std::string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
std::vector<int> lookup(26);

bool getless(const std::string& s1, const std::string& s2)
{
    for (size_t i = 0; i < std::min(s1.size(), s2.size()); ++i)
        if (s1[i] != s2[i])
            return (lookup[toupper(s1[i])-'A'] < lookup[toupper(s2[i])-'A']);
    return s1.size() < s2.size();
};

int main()
{
    StringVect sv = {{ "apple" },{ "pear" },{ "peach" }};

    // build the lookup table
    int i = 0;
    std::for_each(sequence.begin(), sequence.end(), [&](char ch) {lookup[ch-'A'] = i; ++i; });

    // sort the data
    std::sort(sv.begin(), sv.end(), getless);

    // output results
    for (auto& s : sv)
      std::cout << s << "\n";
}

Live Example

A lookup table is built that maps the character's relative ASCII position to where the character is found in the sequence string. So for example, lookup[0] is the position of A (which is 10), lookup[1] is the position of B (which is 23), etc.

The getless function scans the string and tests the character associated with the i'th character of each string with the corresponding lookup position.

The for loop basically "waits for" a character difference in the two strings being compared. If the character in the string for s1 has a lookup value less than the lookup value for the character in s2, then we immediately return "true", meaning that s1 < s2. Otherwise we return false if s1 > s2.

If the characters are equal, we keep looping until we run out of characters to compare. If both strings are equal up to the point we exit the for loop, we return true or false, depending on the length of the strings (a shorter string would mean s1 < s2).

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • Have you noticed that your live example gets the wrong answer? The desired result is pear < peach < apple while your live example gives the order peach < pear < apple. – Frank Boyne Feb 22 '17 at 05:20
  • Comparing `sequence[toupper(s1[i]) - 'A'] < sequence[toupper(s2[i]) - 'A']` doesn't do what you seem to think it does. For example, 'R' is 0x52 so 'R' - 'A' is 0x11 or 17 decimal. Meanwhile 'C' is 0x43 so 'C' - 'A' is 0x02 or 2 decimal. Comparing sequence[17] and sequence[2] is comparing 'K' and 'E'. Since 'E' < 'K' your code will sort PEA**C**H before PEA**R** which is the wrong way round. – Frank Boyne Feb 22 '17 at 05:30
  • @FrankBoyne I realized the error and corrected the example. There were actually two issues, one with the lookup table, and that the function should return the lesser length of the two strings if the loop ends without returning true or false in the `getless` function. – PaulMcKenzie Feb 22 '17 at 15:07