What's wrong with my vector-intersection function? - c++

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}

Related

Suppose we have two std::vectors v1 and v2 and we dont want to combine these in a struct. How to transform v2 the same way v1 was transformed by sort?

This is a followup of this question. The only difference is the constrain that the two vectors cannot be combined in a struct.
Suppose we have a vector
std::vector<double> v1 = {9.0,5.0,3.0,2.0,1.0};
Now we sort the vector v1. Let v2 be given by
std::vector<std::string> v2 = {"you?","are","how","there","hello"};
How to transform v2 the same way v1 was transformed by sort?
Based on this answer, you can use an array of indices to "sort" the vector of doubles, and just use the resulting index array to index the vector of strings.
#include <algorithm>
#include <iostream>
#include <string>
#include <numeric>
int main()
{
std::vector<double> v1 = {5.0,9.0,3.0,2.0,1.0};
std::vector<std::string> v2 = {"are", "you?","how","there","hello"};
// Create an array of indices, starting from 0
std::vector<int> index(v1.size());
std::iota(index.begin(), index.end(), 0);
// "Sort" the index array according to the value in the vector of doubles
std::sort(index.begin(), index.end(),
[&](int n1, int n2){ return v1[n1] < v1[n2]; });
// Output results
for (auto i : index )
std::cout << v2[i] << " " << v1[i] << ", index is " << i << "\n";
}
Output:
hello 1, index is 4
there 2, index is 3
how 3, index is 2
are 5, index is 0
you? 9, index is 1
Note:
I changed the original data to illustrate how the index array works.
The abstraction you are missing is the ability to view the vectors as one item. That's the role that a vector of indices is a proxy for in another answer.
I think it is worth mentioning that there are libraries that provide such a concept (often under the name "zip"). For example, with range-v3:
std::vector<double> v1 = {5, 9, 3, 2, 1};
std::vector<std::string> v2 = {"are", "you?", "how", "there", "hello"};
// Sort the vectors
ranges::actions::sort(ranges::views::zip(v1, v2));
// Output results
for (std::size_t i = 0; i < v1.size(); ++i)
std::cout << v2[i] << " " << v1[i] << ", index is " << i << "\n";
A possible solution uses a helper std::vector<int>:
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>
template<typename T>
void MySort(std::vector<T> t, std::vector<int>& helper)
{
struct StructHelper
{
T t1;
int num;
StructHelper(T t, int i): t1{t}, num{i} {};
bool operator<(const StructHelper& other) const
{ return t1 < other.t1; }
};
std::vector<StructHelper> shVector;
for(int i=0; i<t.size(); ++i)
{
shVector.emplace_back(t[i], i);
}
std::sort(shVector.begin(), shVector.end());
helper = std::vector<int>(t.size());
for(int i=0; i<t.size(); ++i)
{
helper[i] = shVector[i].num;
}
}
template<typename T>
void MySortUsingHelper(std::vector<T>& t1, const std::vector<int>& helper)
{
if(t1.size() != helper.size()) throw std::out_of_range("not same size");
std::vector<T> t2(t1.size());
for(int i=0; i<helper.size(); ++i)
{
t2[i] = t1[helper[i]];
}
t1 = t2;
}
int main() {
std::vector<double> v1 = {9.0,5.0,3.0,2.0,1.0};
std::vector<int> helper;
MySort(v1, helper);
std::vector<std::string> v2 = {"you?","are","how","there","hello"};
MySortUsingHelper(v2, helper);
for(auto elem : v2)
{
std::cout << elem << " ";
}
return 0;
}
You can run the above code online to see the following output:
hello there how are you?

Looping over vector of vectors and appending to a new vector

I want to loop over vect, call a function on each element, perform an operation between both the results and append that to a new vector.
Is there a better way to do this?
std::vector<int> vect = {{1,2},{3,4}};
std::vector<double> out(vect.size());
for (int i = 0; i < vect.size(); i++){
double v = somefunction(vect[i][0]) - somefunction(vect[i][1]);
out.push_back(v);
}
This is what std::transform can be used for.
#include <algorithm>
std::vector<double> out(vect.size());
std::transform(vect.cbegin(), vect.cend(), out.begin(), [](const auto& inner)
{ return somefunction(inner.front()) - somefunction(inner.back()); });
This assumes that vect is a container of size 2 with front() and back() member functions that do what one would expect them to do.
Assuming your vect is a std::vector <std::vector <double>> as it seems to be, you could simply write:
std::vector <double> out;
for(size_t i = 0; i < vect.size(); ++i)
{
out.push_back(someFunction(vect[i][0]) - someFunction(vect[i][1]));
}
or
std::vector <double> out;
for(auto & v : vect)
{
out.push_back(someFunction(v[0]) - someFunction(v[1]));
}
You don't have to initialize out as you did because push_back() will add another element at the end of what you already have added in the construction.
Note that if vect only contains vectors of size two, you can use std::pair instead, for example:
std::vector<std::pair<double, double>> vect;
And replace the previous loop by:
std::vector <double> out;
for(size_t i = 0; i < vect.size(); ++i)
{
out.push_back(someFunction(vect[i].first) - someFunction(vect[i].second));
}
or
std::vector <double> out;
for(auto & v : vect)
{
out.push_back(someFunction(v.first) - someFunction(v.second));
}

Vector comparison

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).

How to compare vector?

How to compare two vectors? Both cointains integer values:
void interaction(vehicles::position &pos, int number, enviroment object)
{
for (auto i = object.x.begin(); i<object.x.end(); i++)
for (auto j = object.y.begin(); j<object.y.end(); j++)
if (pos.x[number] == object.x[i] && pos.y[number] == object.y[j])
cout << "\nInteraction\n";
}
First vector (declared in class):
int remaining_move;
struct position{
vector<int> x;
vector<int> y;
}pos;
Second:
struct enviroment
{
vector<int> x;
vector<int> y;
string graphic;
};
Errors:
object.x[i]
This is wrong. It would work if i were a numeric index, but it's not: it's an iterator.
Instead:
*i
I therefore further suggest calling it something other than i; how about it?
Also, your inner loop condition is wrong. You wrote i, rather than j. Twice. [edit: and now you've fixed that in the question, for some reason]
I'd recommend sorting them first, so this is how I would do it:
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
std::vector<int> v3;
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v3));
If you're just looking for pos.x[number] and pos.y[number] in object.x and object.y, respectively, why not just:
auto itX = std::find(object.x.begin(), object.x.end(), pos.x[number]);
auto itY = std::find(object.y.begin(), object.y.end(), pos.y[number]);
if (itX != object.x.end() && itY != object.y.end()) {
std::cout << "\nInteraction\n";
}
To compare one vector element, you compare the value in the slots:
std::vector<int> a;
std::vector<int> b;
//...
if (a[0] == b[0])
{
// elements are equal
}
More elements can be compared by using a loop:
for (unsigned int i = 0; i < a.size(); ++i)
{
if (a[i] != b[i])
{
break;
}
}
One of the thorns is when the vectors are of different sizes. You'll have to decide on what your actions are on that topic.
There are probably some algorithms in <algorithm> that you can use on a vector.

Sort vector of vectors

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/