1

What I have here is two arrays of different types that I'm converting to vectors.

int ham_array[] = {32,71,12,45,26};

char word_array[] = {"cat", "bat", "green", "red", "taxi"};


vector < int > hamvector (ham_array, ham_array + 5);               

vector < char > wordvector(word_array, word_array + 5); 

I am going to call a sort function to sort the elements of ham_array from least to greatest. At the same time, I would like the word_array to also get sorted the same way ham_vector gets sorted using references.

For example,

after I call sort(hamvector)

ham_array[] = {12, 26, 32, 45, 71}

and sort(wordvector)

word_array[] = {"green", "taxi", "cat", "red", "bat"};

Is there an easy way to do this?

John Flatness
  • 32,469
  • 5
  • 79
  • 81
Mark
  • 11
  • 2
  • 1
    it's same question as http://stackoverflow.com/questions/236172/how-do-i-sort-a-stdvector-by-the-values-of-a-different-stdvector and also similar to http://stackoverflow.com/questions/1577475/c-sorting-and-keeping-track-of-indexes – user534498 Mar 04 '11 at 02:08
  • What sorting criteria do you think would produce *that* result for sorted `word_array`? – ildjarn Mar 04 '11 at 02:16
  • He wants the results in `word_array` to be sorted based on their associated values in `ham_array`. That's what I gathered. – Sion Sheevok Mar 04 '11 at 03:13

3 Answers3

1

Well for one thing, that would be char *word_array[], the way you declared it would be a string.

Anyway the way to do this is you declare a structure to keep these things paired:

struct t {string name; int number;};
vector<t> list;
// fill in list

// comparer to compare two such structs
bool comparer(t &a, t &b) { return a.number>=b.number; }

// and to sort the list
sort(list.begin(), list.end(), comparer);
Blindy
  • 65,249
  • 10
  • 91
  • 131
  • 1
    I'm assuming that he's using a structure of arrays layout rather than an array of structures layout for optimization purposes. Ideally, that makes iteration by one of them to find the other easier. – Sion Sheevok Mar 04 '11 at 02:02
0

If by simple, you mean a more direct way then yes. The std::sort() does support sorting of raw arrays as well:

sort(word_array, word_array + 5, wordcmp);

As Blindy showed, you need a comparator function to tell sort how the ordering is suppose to be done for your list of words. Otherwise you'll end up sorting by the memory address that the string resides at instead of by the letters in your string. Something like this should work:

int wordcmp(const char *lhs, const char *rhs)
{
    return strncmp(lhs, rhs, 256) < 0;
}

One other note, in practice you'll want to prefer std::vector over just raw pointer arrays since the latter isn't as safe.

greatwolf
  • 20,287
  • 13
  • 71
  • 105
0

I've tried to find a solution to a similar problem before and ultimately had to sort it manually. Another way I imagine you could do this would be to write a sorter functor that can somehow figure out, based on which string is being sorted, which integer is associated, and sort based on that. This is terribly inefficient, so I would highly advise doing your own manual sorting using std::swap.

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

template<typename KeyType, typename ValueType>
class CMappedSorter
{
    std::map<KeyType, ValueType>* const m_Mappings;
public:
    CMappedSorter(std::map<KeyType, ValueType>* Mappings) : m_Mappings(Mappings)
    {

    }

    bool operator()(KeyType& LHS, KeyType& RHS)
    {
        const ValueType LHSSortingValue = m_Mappings->find(LHS)->second;
        const ValueType RHSSortingValue = m_Mappings->find(RHS)->second;
        return (LHSSortingValue < RHSSortingValue);
    }
};

int main(int argc, char* argv[])
{
    std::vector<int> Integers;
    std::vector<std::string> Strings;

    Integers.push_back(3);
    Integers.push_back(1);
    Integers.push_back(2);

    Strings.push_back("Apple");
    Strings.push_back("Banana");
    Strings.push_back("Cherry");

    std::map<std::string, int> Mappings;

    if(Integers.size() == Strings.size())
    {
        const unsigned int ElementCount = Strings.size();

        // Generate mappings.
        auto StringsIterator = Strings.begin();
        auto IntegersIterator = Integers.begin();
        for(unsigned int i = 0; i < ElementCount; ++i)
        {
            Mappings[*(StringsIterator)] = *(IntegersIterator);
            ++StringsIterator;
            ++IntegersIterator;
        }

        // Print out before sorting.
        std::cout << "Before Sorting" << std::endl;
        std::cout << "Int\tString" << std::endl;
        StringsIterator = Strings.begin();
        IntegersIterator = Integers.begin();
        for(unsigned int i = 0; i < ElementCount; ++i)
        {
            std::cout << *(IntegersIterator) << '\t' << *(StringsIterator) << std::endl;
            ++StringsIterator;
            ++IntegersIterator;
        }

        // Sort
        std::sort(Strings.begin(), Strings.end(), CMappedSorter<std::string, int>(&(Mappings)));
        std::sort(Integers.begin(), Integers.end());

        // Print out after sorting.
        std::cout << "After Sorting" << std::endl;
        std::cout << "Int\tString" << std::endl;
        StringsIterator = Strings.begin();
        IntegersIterator = Integers.begin();
        for(unsigned int i = 0; i < ElementCount; ++i)
        {
            std::cout << *(IntegersIterator) << '\t' << *(StringsIterator) << std::endl;
            ++StringsIterator;
            ++IntegersIterator;
        }
    }
    else
    {
        std::cout << "Error: Number of elements in each container are not equivalent." << std::endl;
    }
}
Sion Sheevok
  • 4,057
  • 2
  • 21
  • 37
  • I guess I didn't explain well enough. I don't want to sort the char in word_array based on letters. I want to sort them based on the position the ham_array will go once its sorted. i.e I want 32 to refer to "cat" , 71 to "bat", and so on. So that wherever the numbers move once they are sorted, the words will correspondingly move to that position! – Mark Mar 04 '11 at 04:03
  • @Mark: That's **exactly** what this code does. Run it your self. If you get a compiler-error about the auto keyword, replace them with the appropriate STL iterator type based on the container they're from. – Sion Sheevok Mar 04 '11 at 13:25