Reputation: 474
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]);
}
Upvotes: 3
Views: 7548
Reputation: 4214
Here are some std-syle generic utilities (standard c++98).
/// 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());
}
//! 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());
Upvotes: 0
Reputation: 4409
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;
}
Upvotes: 2
Reputation: 103
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 !
Upvotes: 0
Reputation: 35440
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.
Upvotes: 2