nevermind18
nevermind18

Reputation: 31

Problems with making vector function from the existing code C++

I have the program that has two vectors of names and ages. It sorts the names vector and keeps the age vector in the correct order to match the sorted name vector. Now, I want to make a function from existing code, but I have some issues.

Existing code:

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

using namespace std;

int main() {
    vector<string> names      {"One", "Two", "Three", "Four", "Five"};
    vector<unsigned int> ages {    1,     2,       3,      4,      5};
    const vector<string> namesCopy = names;

    sort(begin(names), end(names));

    decltype(ages) sortedAges(ages.size());

    for(int i = 0; i < namesCopy.size(); ++i) {
        const auto iter = lower_bound(begin(names), end(names), namesCopy[i]);

        const auto pos = iter - begin(names);

        sortedAges[pos] = ages[i];
    }

    for(int i = 0 ; i < names.size() ; ++i)
        cout << setw(10) << names[i] << setw(4) << sortedAges[i] << '\n' ;
}

Output

Function:

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

using namespace std;

int test(vector<string> testNames, vector<string> testNamesCopy, vector<unsigned int> testAges, vector<unsigned int> testSortedAges) {
    for(int i = 0; i < testNamesCopy.size(); ++i) {
        const auto iter = lower_bound(begin(testNames), end(testNames), testNamesCopy[i]);

        const auto pos = iter - begin(testNames);
        return testSortedAges[pos] = testAges[i];
    }
}

int main() {
    vector<string> names      {"One", "Two", "Three", "Four", "Five"};
    vector<unsigned int> ages {    1,     2,       3,      4,      5};
    const auto namesCopy = names;

    sort(begin(names), end(names));

    decltype(ages) sortedAges(ages.size());

    for(int i = 0 ; i < names.size() ; ++i)
        cout << setw(10) << names[i] << setw(4) << test(names, namesCopy, ages, sortedAges) << '\n' ;
}

Output 2

Upvotes: 2

Views: 181

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 118097

vector<string> names      {"One", "Two", "Three", "Four", "Five"};
vector<unsigned int> ages {    1,     2,       3,      4,      5};

names and ages seem connected in such a way that it'd be best to group them together in a class. We can use a simple struct which, by default, gives you direct access to its members, just like you have access to all the names and ages in your current solution. You can start with this:

struct person { // ... or animal, or thing. Give it a meaningful name.
    std::string name{};
    unsigned age{};
};

Now you can create a std::vector<person> instead of having two unconnected vectors, which makes sorting and general handling of the data a bit of a hassle.

With the above, sorting and printing etc. becomes more straight forward. I've used lambdas to create the sorting functions in the example:

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <tuple> // std::tie
#include <iomanip>

struct person {
    std::string name{};
    unsigned age{};
};

// print one "person"
std::ostream& operator<<(std::ostream& os, const person& p) {
    return os << std::setw(10) << p.name << std::setw(4) << p.age;
}

int main() {
    // one vector with all the persons
    std::vector<person> persons{
        {"One", 1},
        {"Two", 2},
        {"Three", 3},
        {"Four", 4},
        {"Five", 5}
    };

    // sort on name first, age second (if names are equal) - ascending order
    std::sort(persons.begin(), persons.end(), [](const person& a, const person& b) {
        return std::tie(a.name, a.age) < std::tie(b.name, b.age);
    });
    // print the current order:
    for(const auto& p : persons) std::cout << p << "\n";

    std::cout << "--\n";

    // sort on age first, name second (if ages are equal) - ascending order
    std::sort(persons.begin(), persons.end(), [](const person& a, const person& b) {
        return std::tie(a.age, a.name) < std::tie(b.age, b.name);
    });
    // print the current order:
    for(const auto& p : persons) std::cout << p << "\n";
}

Upvotes: 0

Clonk
Clonk

Reputation: 2070

I think you are approaching this the wrong way. Having 2 vector that you sort but have to keep in the same order is error prone. Instead you should use a vector of pair.

std::vector<std::pair<std::string, int>> idendityVec;

Then you can sort by the name (the first element of the pair) by doing

std::sort(idendityVec.begin(), idendityVec.end());

If you want to sort by age, you can declare your own comparaison function and use it in the sort : bool lesserAge(const pair<std::string,int> &a, const pair<std::string,int> &b) { return (a.second < b.second); } std::sort(idendityVec.begin(), idendityVec.end(), lesserAge); Which gives you something like this :

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

bool lesserAge(const std::pair<std::string, int> &a,
               const std::pair<std::string, int> &b)
{
  return (a.second < b.second);
}
int main()
{
  std::vector<std::pair<std::string, int>> idendityVec = {std::make_pair("three", 3), std::make_pair("four", 4), std::make_pair("two", 2), std::make_pair("one", 1)};

  for (auto v : idendityVec)
  {
    std::cout << "Name=" << v.first << ", age=" << v.second << std::endl;
  }
  // Sort by age i.e. second element
  std::sort(idendityVec.begin(), idendityVec.end(), lesserAge);
  for (auto v : idendityVec)
  {
    std::cout << "Name=" << v.first << ", age=" << v.second << std::endl;
  }
  //Sort by name i.e first element
  std::sort(idendityVec.begin(), idendityVec.end());
  for (auto v : idendityVec)
  {
    std::cout << "Name=" << v.first << ", age=" << v.second << std::endl;
  }
}

Upvotes: 2

Related Questions