sorting parallel vectors?

For PPP2, I have to do an exercise whose specs are as follows:

Read five names into a vector<string> name, then prompt the user for
the ages of the people named and store the ages in a vector<double> age.
Then print out the five (name[i], age[i]) pairs. Sort the names (sort(name
.begin(),name.end())) and print out the (name[i], age[i]) pairs. The tricky
part here is to get the age vector in the correct order to match the sorted
name vector . Hint: Before sorting name , take a copy and use that to
make a copy of age in the right order after sorting name. Then, do that
exercise again but allowing an arbitrary number of names.


I could do the rest of it easily, but I don't get how to do the part in the "hint". Any ideas?
"take a copy" as in "create a copy of the names vector".

You have original_names and original_ages.

Copy and sort the names to create sorted_names.

Finally, you want to create a sorted_ages based on those three vectors.
How do I sort a vector based on another? That's what I'm asking about.
use std::distance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>

int main()
{
    std::vector<std::string> names {"Anna", "Stephen", "Holly", "Zack", "Paul"};
    std::vector<double> age {13, 21, 78, 3, 43};
    std::vector<std::string> names_copy = names;
    std::vector<double> age_index;
    std::sort(names.begin(), names.end());
    for (auto itr = names_copy.cbegin(); itr!= names_copy.cend(); ++itr)
    {
        auto c_iter = std::find(names.cbegin(), names.cend(), *itr);
        if(c_iter != names.end())
        {
            age_index.push_back(std::distance(names.cbegin(), c_iter));
        }
    }
}

Last edited on
Thanks. So is c_iter a constant iterator? If so, how does that work?

I noticed that C++17 added parallelism to std::sort(). I wonder if I can use that in VS2015? Or will I need VS2017 for that? If I can't use that, I'll use your idea since it's great.

I'll just write a separate function to do that in, though. Keep main only for controlling the program and calling the other functions.
is c_iter a constant iterator?

try this:
1
2
//#include <typeinfo>
std::cout << typeid(c_iter).name() << '\n';


I noticed that C++17 added parallelism to std::sort()


OP: I've reading up a bit about this since your mention and, just to make sure, it does not actually mean sorting two containers in parallel to each other (as in your problem). Rather it refers to sorting the left half and right half of the same container concurrently (in parallel) and then merging the results.

Some details here:
https://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode_using.html
Oh, okay. So the STL doesn't support this directly. Got it, thanks for the info.

Edit: How do I actually do the sorting, then? I don't want just the index of the other vector, I want to sort the ages vector based on the names vector.
Last edited on
No, you don't want to "sort".

You do look at each name. Say "Jane Doe" is at:
index 2 in unsorted names
index 7 in sorted names

You then take age from index 2 of the unsorted ages and put it in the index 7 into the sorted ages.

You are free to use iterators or indices as you see fit.



Obviously a trivial solution to sorting would be a std::vector<std::pair<std::string,int>> but that does not require you to manage multiple vectors and is thus not the topic of your current homework.
How do I switch vector indices out like that? That code that Gunnerfunner posted gives me the indices, so now I have to use them to sort the ages vector, but I don't know how to switch the elements based on index positions.

This is what I have right now:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// chapter8ex7.cpp : Defines the entry point for the console application.
// Osman Zakir
// 1 / 13 / 2017
// Bjarne Stoustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 8 Exercise 7
// Exercise Specifications
/**
 * Read five names into a vector<string> name , then prompt the user for
 * the ages of the people named and store the ages in a vector<double> age .
 * Then print out the five ( name[i] , age[i] ) pairs. Sort the names ( sort(name
 * .begin(),name.end()) ) and print out the ( name[i] , age[i] ) pairs. The tricky
 * part here is to get the age vector in the correct order to match the sorted
 * name vector . Hint: Before sorting name , take a copy and use that to
 * make a copy of age in the right order after sorting name . Then, do that
 * exercise again but allowing an arbitrary number of names.
 */

#include "../../std_lib_facilities.h"
#include <iterator>

vector<string> get_names_input();
vector<double> get_ages_input();
vector<double> find_indexes(vector<string> &names, vector<double> &ages);
void parallel_sort(const vector<double> &indexes, vector<double> &ages);
void print_vectors(const vector<string> &names, const vector<double> &ages);

int main()
{
	vector<string> names = get_names_input();
	vector<double> ages = get_ages_input();
	vector<double> indexes = find_indexes(names, ages);
	parallel_sort(indexes, ages);
	print_vectors(names, ages);
	keep_window_open();
}

vector<string> get_names_input()
{
	cout << "Please enter 5 names: ";
	string name;
	vector<string> names;
	do
	{
		cin >> name;
		cin.ignore();
		names.push_back(name);
	} 
	while (names.size() < 5);
	return names;
}

vector<double> get_ages_input()
{
	cout << "Please enter those people's ages: ";
	double age;
	vector<double> ages;
	do
	{
		cin >> age;
		cin.ignore();
		ages.push_back(age);
	} 
	while (ages.size() < 5);
	return ages;
}

vector<double> find_indexes(vector<string> &names, vector<double> &ages)
{
	vector<string> names_copy = names;
	vector<double> age_index;
	sort(names.begin(), names.end());
	for (auto iter = names_copy.cbegin(); iter != names_copy.cend(); ++iter)
	{
		auto c_iter = find(names.cbegin(), names.cend(), *iter);
		if (c_iter != names.end())
		{
			age_index.push_back(distance(names.cbegin(), c_iter));
		}
	}
	return age_index;
}

void print_vectors(const vector<string> &names, const vector<double> &ages)
{
	for (unsigned i = 0; i < names.size(); ++i)
	{
		cout << names[i] << ", " << ages[i] << '\n';
	}
}

void parallel_sort(const vector<double> &indexes, vector<double> &ages)
{
	for (unsigned i = 0; i < indexes.size(); ++i)
	{
		//TODO
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>

int main()
{
    std::vector<std::string> names {"Anna", "Stephen", "Holly", "Zack", "Paul"};
    std::vector<double> age {13, 21, 78, 3, 43};
    std::vector<std::string> names_copy = names;
    std::vector<double> age_index;
    std::sort(names.begin(), names.end());
    for (auto itr = names_copy.cbegin(); itr!= names_copy.cend(); ++itr)
    {
        auto c_iter = std::find(names.cbegin(), names.cend(), *itr);
        if(c_iter != names.end())
        {
            age_index.push_back(std::distance(names.cbegin(), c_iter));
        }
    }
    std::vector<double> age_copy (5, 0);
    auto itr_age = age.cbegin();
    auto itr_index = age_index.cbegin();
    auto itr_ageCopy = age_copy.begin();
    while((itr_age != age.cend()) && (itr_index != age_index.cend()))
    {
               *(itr_ageCopy + *itr_index ) = *itr_age;
               ++itr_age;
               ++itr_index;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iomanip>

int main()
{
    std::vector<std::string> names { "Anna", "Stephen", "Holly", "Zack", "Paul" } ;
    std::vector<unsigned int> ages {     13,        21,      78,     3,     43 } ;

    const auto names_copy = names ; // Before sorting name , take a copy

    std::sort( std::begin(names), std::end(names) ) ; // sort names

    // use that (copy of names)to make a copy of age in the right order
    decltype(ages) sorted_ages( ages.size() ) ; // just large enough to hold all the ages

    for( std::size_t i = 0 ; i < names_copy.size() ; ++i ) // for each name in the copy of names
    {
        // determine its position in the sorted vector
        // random access iterator, sorted sequence; ergo use binary search
        // this may be important for the second part of the exercise:
        // "Then, do that exercise again but allowing an arbitrary number of names".
        // see: http://en.cppreference.com/w/cpp/algorithm/lower_bound
        const auto iter = std::lower_bound( std::begin(names), std::end(names), names_copy[i] ) ;
        const auto pos = iter - std::begin(names) ; // the name will always be found; so no check for end

        // place the age corresponding to this name in the right place in the sorted ages vector
        sorted_ages[pos] = ages[i] ;
    }

    // finally print out a sorted list of names and ages
    for( std::size_t i = 0 ; i < names.size() ; ++i )
        std::cout << std::setw(10) << names[i] << std::setw(4) << sorted_ages[i] << '\n' ;
}

http://coliru.stacked-crooked.com/a/caa185ffa053b682
Thanks. That helped. I got it.
Topic archived. No new replies allowed.