How to compare vector? - c++

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.

Related

Deleting both an element and its duplicates in a Vector in C++

I've searched the Internet and known how to delete an element (with std::erase) and finding duplicates of an element to then delete it (vec.erase(std::unique(vec.begin(), vec.end()),vec.end());). But all methods only delete either an element or its duplicates.
I want to delete both.
For example, using this vector:
std::vector<int> vec = {2,3,1,5,2,2,5,1};
I want output to be:
{3}
My initial idea was:
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
int passedNumber = 0; //To tell amount of number not deleted (since not duplicated)
for (int i = 0; i != vec.size(); i = passedNumber) //This is not best practice, but I tried
{
if (vec[i] == vec[i+1])
{
int ctr = 1;
for(int j = i+1; j != vec.size(); j++)
{
if (vec[j] == vec[i]) ctr++;
else break;
}
vec.erase(vec.begin()+i, vec.begin()+i+ctr);
}
else passedNumber++;
}
}
And it worked. But this code is redundant and runs at O(n^2), so I'm trying to find other ways to solve the problem (maybe an STL function that I've never heard of, or just improve the code).
Something like this, perhaps:
void removeDuplicatesandElement(std::vector<int> &vec) {
if (vec.size() <= 1) return;
std::sort(vec.begin(), vec.end());
int cur_val = vec.front() - 1;
auto pred = [&](const int& val) {
if (val == cur_val) return true;
cur_val = val;
// Look ahead to the next element to see if it's a duplicate.
return &val != &vec.back() && (&val)[1] == val;
};
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}
Demo
This relies heavily on the fact that std::vector is guaranteed to have contiguous storage. It won't work with any other container.
You can do it using STL maps as follows:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
void retainUniqueElements(vector<int> &A){
unordered_map<int, int> Cnt;
for(auto element:A) Cnt[element]++;
A.clear(); //removes all the elements of A
for(auto i:Cnt){
if(i.second == 1){ // that if the element occurs once
A.push_back(i.first); //then add it in our vector
}
}
}
int main() {
vector<int> vec = {2,3,1,5,2,2,5,1};
retainUniqueElements(vec);
for(auto i:vec){
cout << i << " ";
}
cout << "\n";
return 0;
}
Output:
3
Time Complexity of the above approach: O(n)
Space Complexity of the above approach: O(n)
From what you have searched, we can look in the vector for duplicated values, then use the Erase–remove idiom to clean up the vector.
#include <vector>
#include <algorithm>
#include <iostream>
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
if (vec.size() < 2)
return;
for (int i = 0; i < vec.size() - 1;)
{
// This is for the case we emptied our vector
if (vec.size() < 2)
return;
// This heavily relies on the fact that this vector is sorted
if (vec[i] == vec[i + 1])
vec.erase(std::remove(vec.begin(), vec.end(), (int)vec[i]), vec.end());
else
i += 1;
}
// Since all duplicates are removed, the remaining elements in the vector are unique, thus the size of the vector
// But we are not returning anything or any reference, so I'm just gonna leave this here
// return vec.size()
}
int main()
{
std::vector<int> vec = {2, 3, 1, 5, 2, 2, 5, 1};
removeDuplicatesandElement(vec);
for (auto i : vec)
{
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}
Output: 3
Time complexity: O(n)

fastest way to get the maximal difference between 2 vectors

I would like to get ideas for finding a fast way to get the maximal difference between 2 vectors as if they're accumulated .
For example, (not accumulated yet)
vector<int> vec1 = {10, 30, 20, 40 };
vector<int> vec2 = {5, 10, 5, 8 };
the naive way to get the result, is to accumulate them first into new vectors so:
vector<int> accumulated_vec1 = {10, 10+30, 10+30+20, 10+30+20+40};
vector<int> accumulated_vec2 = {5, 5+10, 5+10+5, 5+10+5+8};
i.e:
accumulated_vec1 = {10,40,60,100};
accumulated_vec2 = {5,15,20,28};
Then, the result is the max between abs(accumulated_vec1[i]-accumulated_vec2[i]) while 0 <= i <= 3.
so result = 72 (when i==3)
a faster way can be by representing the vectors by 1 number(even 0.10302040)... but I can't find it helpful :\ Think that I have millions pairs of the 2 vectors vec1 and vec2, and I am trying to avoid calculating the accumulated vectors for each of pair.. sorry if it's not clear but if I find a solution, I'll answer this annoying question.
Fastest way...
int maxDiff(const vector<int> &v1, const vector<int> &v2) {
int maxDiff(0), diff(0);
for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++it1, ++it2) {
diff += *it1-*it2;
maxDiff = max(abs(diff), maxDiff);
}
return maxDiff;
}
No other vector construction, just moving pointers that are even faster than getting elements per their index each time.
Live Demo
Take a look at the code below. Does this do what you are asking?
vector<int> accumulated_vec;
accumulated_vec.resize(vec1.size());
accumulated_vec[0] = vec1[0] - vec2[0];
for(int i = 1; i < accumulated_vec.size(); i++)
{
accumulated_vec[i] = accumulated_vec[i-1] + (vec1[i] - vec2[i]);
cout << accumulated_vec[i] << endl;
}
Here is my version for your problem
int getAccumulatedForIndex(int index, vector<int> &vec) {
if (index == 0) {
return vec.at(index);
}
return vec.at(index) + getAccumulatedForIndex(index - 1, vec);
}
and than
int getAccumulatedMax(vector<int> vec1, vector<int> vec2) {
if (vec1.size() != vec2.size()) { // don't much each other
return -1;
}
int max = -1;
for (int i = 0; i < vec1.size(); ++i) {
int currentMax = abs(getAccumulatedForIndex(i, vec1) - getAccumulatedForIndex(i, vec2));
if (currentMax > max) {
max = currentMax;
}
}
return max;
}
hope that's it what you want

Adding remaining items to another vector

I have an std::vector<unsigned int> v with some índices (for performance purposes I can't use std::set.
I want to create the negated version of v, i.e., the vector with all the remaining indices. If, in a range [0,10], v=[0,2,4,6,8], I want the negated version, nv=[1,3,5,7,9].
Note: v is sorted!
What is the most effective way of doing so?
It is linear time.
std::vector<unsigned int> getnv(unsigned rangebeg, unsigned rangeend, const std::vector<unsigned int>& v)
{
std::vector<unsigned int> nv;
nv.reserve(rangeend - rangebeg - v.size());
std::vector<unsigned int>::const_iterator next = v.begin();
// skip out-of-range values in v
while (next != v.end() && *next < rangebeg) {
++next;
}
for (unsigned i = rangebeg; i < rangeend; ++i)
{
if (next != v.end() && *next == i) {
++next;
continue;
}
nv.push_back(i);
}
return nv;
}
It seems the array v[a,b,c......] is already sorted.
Then, initialse vn=[] and traverse through the elements and insert nos from v[i-1] to v[i] into vn[].
Code:
void insert_nos(int A, int B)
{
for(int i=A+1;i<B;i++)
vn.push_back(i);
}
insert_nos(range_start-1, v[0]);
for(int i=0;i<v.size()-1;i++)
insert_nos(v[i],v[i+1]);
insert_nos(v[v.size()-1],range_end+1);
Make sure to handle the boundary cases.
Complexity: O(n)
Here's a version without raw loops:
std::array<int, 2> range{0,10};
std::vector<int> items{0, 1, 2, 4, 5, 9};
std::vector<int> v(range.back() - range.front() - items.size());
std::generate(v.begin(), v.end(),
[iter = items.cbegin(), endIter = items.cend(), i = range.front()] () mutable
{ while(iter < endIter && i == *iter) { ++iter; ++i; } return i++; });

extracting the elements from specified indexes in c++ vector

I have two questions, Any help will be highly appriciated.
I have a matrix A ={ 0 1 0 0 1 1 0 0}. Now I found the locations of 0's indexes and saved in the vector B={0 2 3 6 7}.
How Can I extract the elemnents indexed by vector B in A to a new vector, without damaging original vector A? i.e. I want to get C= {0 0 0 0 0} which is the data from A, indexed by B.
How can I erase the elements in A indexed by B?
I tried something like this for question no. 2,but did not suceed.
///// erasing the elements in particular locations
sort (B.begin(), B.end());
for(int i=A.size() - 1; i >= 0; i--){
A.erase(A.begin() + B[i]);
}
1.How Can I extarct the elemnents indexed by vector B in A, without damaging original vector A? i.e. I want to get C= {0 0 0 0 0} which is the data from A, indexed by B.
std::vector<int> C;
for (size_t i = 0; i < B.size(); ++i )
C.push_back(A[B[i]]);
Of course, we're assuming that B does not have entries that will go out-of-bounds of the A vector.
Q1:
If you are happy making a new vector, PaulMcKenxie's answer is what you want:
std::vector<int> C;
for (size_t i = 0; i < B.size(); ++i )
C.push_back(A[B[i]]);
Q2:
Otherwise, you need to remove each instance not indexed by B.
This is relatively complex, as by removing an entry the way you did, you force realocation that can/(will?) invalidate your iterators / pointers to the data.
Probably the best solution (simple and efficient) to this is to create a temporary vector C above, and then swapping the reduced data in.
void delete_indexes(std::vector<int> &data, std::vector<int> &indexes)
{
std::vector<int> temp;
for (size_t i = 0; i < indexes.size(); ++i )
{
temp.push_back(data[indexes[i]]);
}
data.swap(temp); //does the work
}
int main()
{
//do stuff
delete_indexes(A,B);
}
The swap option is fast (just swaps instead of removing and writing) and the temp vector (with your original data) is disposed of when it goes out of scope.
Edit:
This answer could also be what you are looking for, assuming you have a function for generating each element of B that you can apply (even if it is A[i] == 1 (code edited to suit):
for(auto it = A.begin(); it != A.end();)
{
if (criteria_for_B(*it))
it = A.erase(it);
else
++it;
}
For me, I use the erase function but with a counter to décrement the iterator :
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> A;
A.push_back(0);
A.push_back(1);
A.push_back(0);
A.push_back(0);
A.push_back(1);
A.push_back(1);
A.push_back(0);
A.push_back(0);
vector<int> B;
B.push_back(0);
B.push_back(2);
B.push_back(3);
B.push_back(6);
B.push_back(7);
for(int i=0; i<A.size(); i++){
cout << A[i] << "-";
}
cout << endl;
vector<int> C = A;
int ii=0;
for(int i=0; i<B.size(); i++){
C.erase(C.begin() -ii + B[i] );
ii++;
}
for(int i=0; i<C.size(); i++){
cout << C[i] << "-";
}
}
You can use a third vector as me or just directly modify A.
I hope that will help you !
Here are some std-syle generic utilities (standard c++98).
1. Extract elements at indices
/// Extract elements from vector at indices specified by range
template <typename ForwardIt, typename IndicesForwardIt>
inline std::vector<typename std::iterator_traits<ForwardIt>::value_type>
extract_at(
ForwardIt first,
IndicesForwardIt indices_first,
IndicesForwardIt indices_last)
{
typedef std::vector<typename std::iterator_traits<ForwardIt>::value_type>
vector_type;
vector_type extracted;
extracted.reserve(static_cast<typename vector_type::size_type>(
std::distance(indices_first, indices_last)));
for(; indices_first != indices_last; ++indices_first)
extracted.push_back(*(first + *indices_first));
return extracted;
}
/// Extract elements from collection specified by collection of indices
template <typename TVector, typename TIndicesVector>
inline TVector extract_at(const TVector& data, const TIndicesVector& indices)
{
return extract_at(data.begin(), indices.begin(), indices.end());
}
2. Remove elements at indices
//! Remove one element with given index from the range [first; last)
template <typename ForwardIt>
inline ForwardIt remove_at(ForwardIt first, ForwardIt last, const size_t index)
{
std::advance(first, index);
for(ForwardIt it = first + 1; it != last; ++it, ++first)
*first = *it;
return first;
}
/*!
* Remove elements in the range [first; last) with indices from the sorted
* range [indices_first, indices_last)
*/
template <typename ForwardIt, typename SortedIndicesForwardIt>
inline ForwardIt remove_at(
ForwardIt first,
ForwardIt last,
SortedIndicesForwardIt indices_first,
SortedIndicesForwardIt indices_last)
{
typedef typename std::vector<bool> flags;
// flag elements to keep
flags is_keep(
static_cast<flags::size_type>(std::distance(first, last)), true);
for(; indices_first != indices_last; ++indices_first)
is_keep[static_cast<flags::size_type>(*indices_first)] = false;
// move kept elements to beginning
ForwardIt result = first;
for(flags::const_iterator it = is_keep.begin(); first != last; ++first, ++it)
if(*it) // keep element
*result++ = *first; //in c++11 and later use: *result++ = std::move(*first);
return result;
}
Usage (erase-remove idiom):
std::vector<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> ii{6, 3, 1};
std::sort(ii.begin(), ii.end());
vec.erase(remove_at(vec.begin(), vec.end(), ii.begin(), ii.end()), vec.end());

What's wrong with my vector-intersection function?

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}