I have
vector<vector<int>> vec
in my c++ app.
Every vector of integers as an element of "big" vector has 4 INT values.
I want to sort vec basing on third value of it's content vectors of ints (I mean every "inside" vector third element) - is it possible?
EDIT
Let's say I've got a function
COST(vector<int>)
which calculates me some value based on my vector values - can I use it in comparation parameter too? It'd help me a lot more.
Sure it is. std::sort can take a third parameter which is the comparison function to use when sorting. For example, you could use a lambda function:
std::vector<std::vector<int>> vec;
// Fill it
std::sort(vec.begin(), vec.end(),
[](const std::vector<int>& a, const std::vector<int>& b) {
return a[2] < b[2];
});
Alternatively, you can pass anything else callable with signature bool(const std::vector<int>&, const std::vector<int>&), such as a functor or function pointer.
Response to edit: Simply apply your COST function to a and b:
std::sort(vec.begin(), vec.end(),
[](const std::vector<int>& a, const std::vector<int>& b) {
return COST(a) < COST(b);
});
If you want to compare the two vectors by cost, try this:
bool predicate(const std::vector<int>& a, const std::vector<int>& b)
{
return COST(a) < COST(b);
}
Notes:
The above works with C++98, too, I'm not sure about how widespread the use of C++11 is and whether you have a compliant compiler. Otherwise, you can of course use a lambda expression, too, as sftrabbit suggested.
You don't say what COST returns, I simply assumed some sortable value like float or long.
I hope you don't copy the vector when passing it to COST(), that would be horribly inefficient.
COST suggests a macro, like all UPPERCASE_NAMES. Don't use macros. Don't use macro names for functions.
sort(vec.begin(), vec.end(), comp);
where comp is:
static bool comp(const vector<int>& vec1, const vector<int>& vec2){
return vec1[2] < vec2[2];
}
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
// This makes the sort be according to column 2 and ascending
bool sortFunc( const vector<int>& p1,
const vector<int>& p2 ) {
return p1[1] < p2[1];
}
int main() {
srand(time(NULL));
// Creates and initializes 10 x 4 vector
vector< vector<int> > vec;
for( int i=0; i<10; i++ ) {
vector<int> tmpVec;
for( int j=0; j<2; j++ ) {
tmpVec.push_back( rand()%10 );
}
vec.push_back( tmpVec );
}
// Print out the pre-sorted vector
cout << "Pre-sorting state:" << endl;
for( int i=0; i<vec.size(); i++ ) {
for( int j=0; j<vec[i].size(); j++ ) {
cout << vec[i][j] << " ";
}
cout << endl;
}
cout << endl;
// Do the sorting according to column 2
sort(vec.begin(), vec.end(), sortFunc);
// Print out the post-sorted vector
cout << "Post-sorting state:" << endl;
for( int i=0; i<vec.size(); i++ ) {
for( int j=0; j<vec[i].size(); j++ ) {
cout << vec[i][j] << " ";
}
cout << endl;
}
return 0;
}
source: https://shihho.wordpress.com/2012/11/28/sort_with_vectors/
Related
Vector function emplace()
My emplace function does not work. Any help would be appreciated
vector <int> vec1;
vector <int> vec2(4,0);
vector <int>::iterator iter1;
vector <int>::iterator iter2;
srand(time(NULL));
for(i=0; i<5; i++){
n =rand()%10+1;
vec1.push_back(n);
}
for(iter1=vec1.begin();iter1<vec1.end();iter1++){
for(iter2=vec2.begin();iter2<vec2.end();iter2++){
if(*iter1<=*iter2){
//vec2.emplace(iter1,*iter1);
//print();
}
}
}
for(iter2=vec2.begin();iter2<vec2.end();iter2++){
Because vec2 starts populated with four values of 0, you will never find an element where *iter1 <= *iter2 unless *iter1 == 0.
Instead of zero-initializing it to avoid allocations, you want to reserve space.
vec2.reserve(vec1.size());
and then instead of a for loop you can use std::lower_bound to find the insert location:
#include <iostream>
#include <vector>
#include <algorithm>
void print_vec(const char* label, const std::vector<int>& vec) {
std::cout << label << ": ";
for (int v : vec) {
std::cout << v << ", ";
}
std::cout << "\n";
}
int main() {
std::vector <int> vec1 { 4, 1, 2, 2, 5 };
std::vector <int> vec2;
print_vec("v1", vec1);
vec2.reserve(vec1.size());
for (int v : vec1) {
auto it = std::lower_bound(vec2.begin(), vec2.end(), v);
if (it == vec2.end() || *it != v)
vec2.emplace(it, v);
print_vec("v2", vec2);
}
print_vec("Fin", vec2);
return 0;
}
Live demo: http://ideone.com/o5td9K
What you are trying to do is like insertion sort.
https://en.wikipedia.org/wiki/Insertion_sort
has the pseudo-code. At each step you will check every element in vector 2 and place the new element where it belongs (while loop).
I'm trying to change the data inside a vector's element by using a function. It happens that the elements are changed just inside the function. How can I keep the changings outside the function? Do I must use pointers?
The code:
#include <iostream>
#include <vector>
using namespace std;
void populate( int size_, vector<int> pop)
{
//Set the vector's size and populate the vector
pop.resize(size_);
for(int i = 0; i<3 ; i++)
{
pop[i] = i;
}
}
int main()
{
vector<int> vec;
int size = 3;
populate(size, vec);
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
The output at cout should be : 0 1 2
But it is empty.
What you're trying to do is easily and idiomaticaly done with standard library facilities:
int size = 3;
std::vector<int> vec(size);
std::iota(vec.begin(), vec.end(), 0); // include algorithm for this
You need to take the vector by reference
void populate( int size_, vector<int>& pop)
Otherwise you are passing in a copy of the vector, populating it, then returning, but the original vector is unmodified.
Or as #juanchopanza recommended, since the sole purpose of this function is to make this vector for you, it could be
vector<int> populate( int size_ )
{
vector<int> temp(size_);
for(int i = 0; i < size_ ; i++)
{
pop[i] = i;
}
return temp;
}
Then
int main()
{
int size = 3;
vector<int> vec = populate(size, vec);
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
You are sending in the vector to populate by value. This creates a copy, so pop is a copy of vec. Changes you make only affect pop.
I'm beginner in programming. Something is giving me trouble to code. Suppose, I've an array.
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
I want to remove all elements which are greater than 9. How can I do this?
You can do this if you use vector. First initialize vector with your array. Then use remove_if() function. Hope this will help.
#include <algorithm>
#include <vector>
int main()
{
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
vector<int> V(Array, Array+20);
vector<int> :: iterator it;
it = remove_if(V.begin(), V.end(), bind2nd(greater<int>(), 9));
V.erase (it, V.end()); // This is your required vector if you wish to use vector
}
You cannot remove items from an array, since they are fixed in size.
If you used std::vector, then the solution would look like this:
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
std::vector<int> Array = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
Array.erase(remove_if(Array.begin(), Array.end(), [](int n) { return n > 9; }),
Array.end());
copy(Array.begin(), Array.end(), ostream_iterator<int>(cout, " "));
}
Live example: http://ideone.com/UjdJ5h
If you want to stick with your array, but mark the items that are greater than 10, you can use the same algorithm std::remove_if.
#include <algorithm>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
int *overwrite_start = remove_if(std::begin(Array), std::end(Array), [](int n){ return n>9; });
fill(overwrite_start, std::end(Array), -1);
copy(std::begin(Array), std::end(Array), ostream_iterator<int>(cout, " "));
}
The above will move the "erased" items to the end of the array, and mark them with -1.
Live example: http://ideone.com/7rwaXy
Note the usage in both examples of the STL algorithm functions. The second example with the array uses the same remove_if algorithm function. The remove_if returns the start of the "erased" data, as remove_if doesn't actually remove, but moves the data to the end of the sequence.
i am try swap concept without using vector
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
int n;
int arr_len = sizeof(Array)/sizeof(int);
void print_array_value() {
int i;
cout << "\n";
for (i = 0; i < arr_len; i++) {
cout << Array[i] << ", ";
}
cout << " : " << arr_len << "\n";
}
void swap_array_value(int start) {
int i;
for ( ; (start+1) < arr_len; start++) {
Array[start] = Array[start+1];
}
}
void remove_array_value() {
int i;
for (i = 0; i < arr_len; i++) {
if (Array[i] > n) {
swap_array_value(i);
arr_len--;
i--;
}
}
}
void main () {
clrscr();
cout << "Enter the N value : ";
cin >> n;
print_array_value();
remove_array_value();
print_array_value();
cout << "Array Length : " << arr_len;
getch();
}
I have a function that accepts two vectors v1 and v2. Compares the elements in both of them and is supposed to return the common elements from both. Both vectors have 5 strings in them.
It doesn't work as expected, though. For example, I enter for v1:
dog cat lizard snake pig
and v2 has:
cat sheep cow snake fish
The result though is:
snake
How can I fix it so that the output would look something like the follow?
cat snake
my code
#include <iostream>
#include <vector>
#include <string>
using namespace std;
const int CAPACITY = 5;
template <typename t>
vector <t> inter(const vector <t> & v1, const vector <t> & v2)
{
vector <t> v3;
for(int i = 0; v1.size(); i++ )
{
for(int j= 0; v2.size(); j++)
{
if (v1[i] == v2[j])
{
v3.push_back(v1[i]);
}
}
}
return v3;
}
int main()
{
vector<string> vec1;
string a;
cout << "Enter five stings for vector 1 \n"<< endl;
for(int i = 0; i< CAPACITY; i++ )
{
cin >> a;
vec1.push_back(a);
}
vector<string> vec2;
string b;
cout << "Enter five stings for vector 2 \n"<< endl;
for(int i = 0; i< CAPACITY; i++ )
{
cin >> b;
vec2.push_back(b);
}
cout<<inter(vec1, vec2);
}
One option is to sort both vectors, and then use std::set_intersection.
Use std::set_intersection algorithm is much easier, it requires two sorted vectors:
template <typename T>
std::vector<T> inter(const std::vector<T> & v1, const std::vector<T> & v2)
{
std::vector<T> v3;
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v3));
return v3;
}
std::sort(vec1.begin(), vec1.end()); // sort vec1
std::sort(vec2.begin(), vec2.end()); // sort vec2
std::vector<std::string> v3 = inter(vec1, vec2);
See sample code
Well, your inter function has a few problems:
The return type is a single element
Two unused local variables
Only tests each element against the one in the identical position in the other set
For the inter function, first change the return type to a vector, then use the v3 vector you are currently not using for the below operations.
vector<t> inter(const vector <t> & v1, const vector <t> & v2)
{
vector<t> v3;
for(int i=0; i<v1.size(); i++)
{
for(int j=0; j<v2.size(); j++)
{
if(v1[i] == v2[j])
{
v3.push_back(v1[i])
}
}
}
return v3;
}
To print out the contents you have to assign the returned vector to a variable and then loop through it as such...
vector<t> vec3 = inter(vec1, vec2);
for(int i=0; i<vec3.size(); i++)
{
cout<<vec3.at(i)<<" ";
}
That will return a vector containing all of the answers, make sure to make the changes to the loop as before your loop was only checking if they were in the same place, not if they were both in the vector
Be mindful that this will produce duplicate results in the case of {x, x, y} and {x, z , a}
I'm trying to sort a vector v1 using another vector v2. I can't wrap my head around this error:
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check
Abort trap
while running this code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Comp
{
public:
Comp(vector<double>& inVec): _V(inVec) {}
bool operator()(int i, int j) {return (_V.at(i)<_V.at(j));}
private:
vector<double> _V;
};
int main(int argc, char** argv)
{
double x1[] = {90.0, 100.0, 80.0};
double x2[] = {9.0, 3.0, 1.0};
vector<double> v1(x1,x1+3);
vector<double> v2(x2,x2+3);
sort(v1.begin(), v1.end(), Comp(v2)); // sort v1 according to v2
for(unsigned int i=0; i<v1.size(); i++)
{
cout << v1.at(i) << " " << v2.at(i) << endl;
}
return 0;
}
v1 and v2 are of the same size. Why the out_of_range error?
Thanks in advance for any pointers.
I believe that your problem is in this line:
bool operator()(int i, int j) {return (_V.at(i)<_V.at(j));}
The problem is that when the std::sort algorithm uses a custom callback, it passes in the actual values stored in the vector at particular locations, not the indices of those locations within the vector. As a result, when you call
sort(v1.begin(), v1.end(), Comp(v2)); // sort v1 according to v2
The Comp comparator you've written will be getting passed as parameters the values stored in the v1 vector and will then try indexing at those positions into the v2 vector. Since the values in v1 are larger than the size of v2, the call to _V.at(i) will cause an out_of_range exception to be thrown.
If you want to sort the two ranges with respect to one another, you'll need to adopt a different approach. I'm not aware of a straightforward way of doing this, but I'll let you know if I think of one.
Size of v1 is just 3, but you're using each value of v2 as index of v1. And as v2 has one value 9 which is greater than the size of v1, that is what gives std::out_of_range error in here:
bool operator()(int i, int j) {return (_V.at(i)<_V.at(j));}
std::vector::at function gives std::out_of_range exception of the index passed to it as argument is greater than the size of vector. That is, the index must be less than vector::size().
Ok, now you're probably aware of the fact, that i and j are actual values held in vector rather than indices. There is a good reason for that: sorting is all about values, not indexes. Note you're passing iterators to sort method, so there is no way it can extract index for you. Of course, you could get index relative to first iterator, but there is no reason for doing this.
However, let's be insane for awhile and imagine you would get indices rather than values in your comparator. Assume that your code does what you want and let's think about following scenario:
v1 = {20,10}; v2 = {2,1}
I secretly assume you want the following output:
v1 = {10, 20}
right? Now imagine I'm a sorting function you're calling and I do following steps:
v2[0] < v2[1] is false, so swap(&v1[0], &v1[1])
It's sorted, isn't it? But wait, I'm a crazy sorting function, so I want to make sure it's sorted, so I do the following:
v2[0] < v2[1] is false, swap(&v1[0], &v1[1])
And again:
v2[0] < v2[1] is false, swap(&v1[0], &v1[1])
and again, again, again...
Can you see a problem? Sorting function has some requirements and for sure you're breaking fundamental one.
I suspect you need completely different container (maybe std::map with keys from vec1 and values from vec2) or at least something like vector< pair<double, double> >, so you can easily sort by either first or second value. If not, consider creating vector with values in range [0, v2.size()), sorting it using your comparator (values are equal to indices, so will be all right) and then print correct values from v1. This code works fine:
vector<size_t> indices;
for(size_t i =0; i < v1.size(); ++i)
{
indices.push_back(i);
}
// yes, it works using your original comparator
sort(indices.begin(), indices.end(), Comp(v2));
for(size_t i =0; i < indices.size(); ++i)
{
cout << v1.at(indices[i]) << " " << v2.at(indices[i]) << endl;
}
Like said in other answers, the problem is that the sort algorithm passes the actual values to compare rather than indices.
Here is how you can solve it:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<double, double> Zipped; // Represent an element of two lists
// "zipped" together
// Compare the second values of two pairs
bool compareSeconds ( Zipped i, Zipped j )
{
return i.second < j.second;
}
int main ( int argc, char **argv )
{
double x1[] = { 90, 100, 80 };
double x2[] = { 9, 3, 1 };
vector<double> v1(x1, x1 + 3);
vector<double> v2(x2, x2 + 3);
vector<Zipped> zipped(v1.size()); // This will be the zipped form of v1
// and v2
for ( int i = 0; i < zipped.size(); ++i )
{
zipped[i] = Zipped(v1[i], v2[i]);
}
sort(zipped.begin(), zipped.end(), &compareSeconds);
for ( int i = 0; i < zipped.size(); ++i )
{
cout << zipped[i].first << " " << zipped[i].second << endl;
}
for ( int i = 0; i < v1.size(); ++i )
{
v1[i] = zipped[i].first;
}
// At this point, v1 is sorted according to v2
return 0;
}