hammonak
hammonak

Reputation: 1

How can you keep the positions of an array the same while sorting?

I am writing a Caesar cipher decoding program that sorts the frequency of letters of a message in descending order. My issue is when I print out the results the positions of the frequencies in the array no longer match the letters I have set up. How do I fix this? I have other code that removes punctuation and capitals, all characters besides spaces and lowercase letters from the message being decoded.

I have trimmed down the code to just what is being questioned.

#include<iostream>
#include<string>
#include<fstream>

using namespace std;

void sortArray(int*, int);

int main()
{    

    string fileContent = "a coded message which is several hundreds of characters long is being passed into the program";

    int count[26];

// This code is skipping over spaces and other characters

    for(int f = 0; f < fileContent.length(); f++)
    {
            if(fileContent[f] == 32)
            {
                    continue;
            }

            if(fileContent[f] >= 48 && fileContent[f] <= 57)
            {
                    continue;
            }

            count[(fileContent[f]-'a')%26]++;
     }

// Here is where my issue begins. In sortArray, the position of the characters are being changed.

     cout << "Letter frequency: Most common to least common" << endl;

     sortArray(count, 26);

     for(int p = 0; p < 26; p++)
     {
           cout << char(p + 97) << ": " << count[p]  << endl;
     }

    return 0;
}



void sortArray(int* srcArray, int numElements)
{
        for(int x = 0; x < numElements; x++)
        {
            int max = srcArray[x];
            int maxIndex = x;
            int hold;

            for(int y = x + 1; y < numElements; y++)
            {
                    if(srcArray[y] > max)
                    {
                            max = srcArray[y];
                            maxIndex = y;
                    }
            }

            hold = srcArray[x];
            srcArray[x] = max;
            srcArray[maxIndex] = hold;
            hold = 0;

        }
}

Please kindly let me know how I can solve this issue, I've been theorizing but I cannot seem to figure out a viable solution.

Upvotes: 0

Views: 144

Answers (3)

Jive Dadson
Jive Dadson

Reputation: 17026

The answer is probably a three-liner for a standard library guru, which I am not quite yet. I hate the standard library. It makes programming so easy that anyone can do it.

Here are two versions that I hacked out. This is fun.

#include <map>
#include <string_view>
#include <vector>
#include <algorithm>
using counted = std::pair<char, unsigned>;

std::vector<counted> 
counted_chars(const std::string_view input) {
  // Return a vector of <char, count> pairs, where char is an uppercase
    // letter, and count is the number of occurrences of the letter (upper or lower).
    // It is sorted from highest count to lowest.
    using namespace std;
    map<char, unsigned> count;
    // Count them.
    for(char next: input) {if (isalpha(next)) {count[toupper(next)] += 1;}}

    // Sort them
    vector<counted> sorted(count.size());
    copy(count.cbegin(), count.cend(), sorted.begin());
    sort(sorted.begin(), sorted.end(), [](counted c1, counted c2) 
      { return c1.second > c2.second; });

    return sorted;
}

int main() {
    std::string str = "a coDed; MESSage which_is several hundreds of characters long is being passed into the program";
    auto result = counted_chars(str);
    return 0;
}

Another one that doesn't use std::map.

#include <map>
#include <vector>
#include <algorithm>
using counted = std::pair<char, unsigned>;

std::vector<counted> counted_chars(std::string input) {

    using namespace std;
    input.resize(remove_if(input.begin(), input.end(), [](char ch) { return !isalpha(ch); })-input.begin());
    for(char &ch: input) { ch = toupper(ch); }
    sort(input.begin(), input.end());
    string present {input};
    present.resize(unique(present.begin(), present.end())-present.begin());
    std::vector<counted> sorted;
    for (char ch:present) {sorted.push_back(make_pair(ch, count(input.begin(), input.end(), ch)));}
    sort(sorted.begin(), sorted.end(), [](counted c1, counted c2) { return c1.second > c2.second; });
    return sorted;
}

int main() {
    std::string str = " -- I have always wished for my computer to be as easy to use as my telephone; My wish has come true because I can no longer figure out how to use my telephone.";
    auto result = counted_chars(std::move(str));

    return 0;
}

Upvotes: 0

Valgrind1691
Valgrind1691

Reputation: 300

The problem you are facing is because you have frequencies in the array but the frequencies are not mapped to corresponding character. When the frequencies are sorted,the array is rearranged but your printing of the frequencies is not character dependent,you are printing characters from a-z and assigning frequencies as they are in sorted array.

What you can do is map the frequencies with corresponding character. One solution can be using an unordered map,char being key. An unordered map because it won't internally sort the map on character value,so u can maintain frequency ordering as well.

You can also use vector with pair as @lamandy suggested.

vector< pair <char, int> > vect;
for (int i = 0; i < 26; i++)
{
    vect.push_back(make_pair(char(i + 97), count[i]));
}

sort(vect.begin(), vect.end(), sortbysecVal);

// Printing the sorted vector(after using sort())
cout << "The vector after sort operation is:\n";
for (int i = 0; i<26; i++)
{
    // "first" and "second" are used to access
    // 1st and 2nd element of pair respectively
    cout << vect[i].first << " "
        << vect[i].second << endl;
}

sort by second value of pair

bool sortbysecVal(const pair<int, int> &a,  const pair<int, int> &b)
  return (a.second > b.second);

Once after you have calculated frequencies,you can use this,this will solve your purpose and you wont need your sort function.

P.S : One more thing,you must initialize your (array)count to 0,like int count[26] = {0},because initially it contains garbage if uninitialized and adding up 1 ( count[(fileContent[f]-'a')%26]++;) to a garbage will not produce result(frequency) u expect

Upvotes: 0

lamandy
lamandy

Reputation: 982

After you compute the frequency in count array.

std::array<std::pair<char, int>, 26> pairArray;
for (int i = 0; i < 26; ++i)
{
    pairArray[i] = std::make_pair('a' + i, count[i]);
}

std::sort(pairArray.begin(), pairArray.end(), myCompare);

for (int i = 0; i < 26; ++i)
    std::cout << pairArray[i].first << ": " << pairArray[i].second << std::endl;

For myCompare,

bool myCompare(const std::pair<char, int>& p1, const std::pair<char, int>& p2)
{
    return p1.second > p2.second;
}

This should sort the array in descending order.

Upvotes: 1

Related Questions