Removing fields in c++ vector - c++

I cannot grasp the idea and programm such a thing correctly (I'm a beginner):
I have a vector. Vector has lets say elements: fieldA, fieldB, fieldC. So having array of these vectors, I want to check, beginning with the last vector in the array, and going to the direction of the first one, if one of the elements has a specific value, lets say if (vect[i].fieldA == 0.0). In such a case, if (vect[i-1].fieldA == 0.0) so has the same value, I want to remove the whole vector from array. Can someone provide me with a part of code that will visualize, how to create the proper "back iteration" loop and use function to delete it? I was trying with erase(), remove(), deque() but I failed.
I don't want to mess here with my codes.
Thanks for help!
EDIT. So I first fed in a loop my array with vectors values, then I want to remove all vectors from the end, that contain element specific value, e.g. fieldA == 0.0
I want to cut the array, not only remove content of vectors!
There is proper inheritance between classB and classA so the feeding works well, I want only to solve this thing with deleting the vectors.
example: array of vectors of 2 elements. input: 0,1 0,3 3,3 2,3 0,6 5,6 0,8 0,7 0,6 output:0,1 0,3 3,3 2,3 0,6 5,6 0,8. conclusion: 0,7 and 0,6 vectors were removed.
classA tmp;
for (std::vector<std::classB>::iterator iter = newW.begin(); iter != newW.end(); iter++)
{
tmp.set_fieldA(iter->a);
tmp.set_fieldB(iter->b);
tmp.set_fieldC(iter->c);
objA.push_back(tmp);
}
vector<std::classA> objA;
for(int i = objA.size()-1; i > 0; i--)
{
if (objA[i].fieldA == 0.0)
if (objA[i-1].fieldA == 0.0)
objA.erase(objA[i-1]); //remove last vector from array
}

I'm interpreting your code as follows. You have a struct named Vector with 3 members
struct Vector
{
double fieldA;
double fieldB;
double fieldC;
}
The code below works as follows. It uses std::find_if_not with reverse iterators (rbegin() and rend()) to find the first element from the back that has a fieldA different from 0. It then converts this to a regular iterator (using base()) and compares it to the end of the vector. Finally the call v.erase will actually erase them (the so-called erase-remove idiom)
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
int main()
{
struct Vector { int fieldA; int fieldB; };
std::vector<Vector> v = {
Vector{ 1, 0 }, Vector{ 2, 1 }, Vector{ 0, 2 }, Vector{ 1, 3 }, Vector{ 0, 4 },
Vector{ 0, 5 }, Vector{ 5, 6 }, Vector{ 6, 7 }, Vector{ 0, 8 }, Vector{ 0, 9 }, Vector{ 0, 10}
};
for (auto& e: v) { std::cout << "{" << e.fieldA << "," << e.fieldB << "}, "; };
std::cout << "\n";
auto m = std::find_if_not(v.rbegin(), v.rend(), [&](Vector const& elem){
return elem.fieldA == 0;
}).base();
if (m != v.end())
// remove all but one matching element
v.erase(m + 1, v.end());
for (auto& e: v) { std::cout << "{" << e.fieldA << "," << e.fieldB << "}, "; };
std::cout << "\n";
}
Output on LiveWorkSpace

Related

Counting Duplicates in C++ - multiset?

UPD:-
Value Instances
 2   3
 3   2
 5   1
I want to limit the count to 1 for all the instances present in the multiset.
#include<bits/stdc++.h>
using namespace std;
int main() {
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(3);
p1.insert(2);
p1.insert(2);
for(auto itr : p1) {
if(p1.count(itr) > 1)
p1.erase(itr);
cout << itr;
}
}
How to fix this ?
My comment:
In that case, you should use a std::set<int> because that is actually what matches your requirement. You could use also a std::map<int, int> to map the key to the number of occurrences if you like.
OPs reply:
Can you add this to a full-fledged answer so that I can accept it for this question?
Here we go:
Just filtering duplicates:
#include <iostream>
#include <set>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once
using Table = std::set<int>;
Table table;
for (int value : sample) table.insert(value);
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 2
Value 3
Value 5
Demo on coliru
Counting the number of occurrences:
#include <iostream>
#include <map>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once but count the number of occurrences
using Table = std::map<int, unsigned>;
Table table;
for (int value : sample) ++table[value];
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry.first << " (" << entry.second << " times)\n";
}
}
Output:
Value 2 (3 times)
Value 3 (2 times)
Value 5 (1 times)
Demo on coliru
The trick:
The std::map::operator[] inserts an element if the key is not yet there. This element (in this case std::pair<const int, unsigned>) is default initialized which grants that it starts as { key, 0 }.
So, there are two cases:
The key is not yet there:
The element is created as { key, 0 } and the value (.second of the element) is incremented immediately which results in { key, 1 }.
The key is already there:
The value (.second of the element) is incremented again.
A variation on filtering duplicates:
This keeps the original input order but removes repetitions (by book-keeping in a separate std::set).
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator iterRead = sample.begin();
Sample::iterator iterWrite = sample.begin();
for (; iterRead != sample.end(); ++iterRead) {
if (table.insert(*iterRead).second) *iterWrite++ = *iterRead;
}
sample.erase(iterWrite, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 5
Value 2
Value 3
Demo on coliru
The trick:
std::set::insert() returns a pair of iterator and bool.
The iterator points to the key in the set (inserted or already been there).
The bool denotes if the key was inserted (true) or was already there (false).
The other trick:
Just erasing every found duplicate from the std::vector would result in the worse complexity O(n²).
Hence, two iterators are used, one for reading and one for writing. Thereby, every input value which is not yet in the bookkeeping table (and hence occurs the first time) is written back, otherwise not.
So, every value which occurred the first time is shifted towards the beginning and appended to the previous values which occurred the first time each. Additionally, the iterWrite points past the last written element after the loop and can be used to erase the rest (which contains left input values which are all duplicates).
The complexity of this algorithm is O(n) – much better than the naive approach.
Btw. the standard algorithms std::remove(), std::remove_if() does it the same way.
Thus, the same algorithm could be achieved with std::remove_if():
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator last
= std::remove_if(sample.begin(), sample.end(),
[&](int value) { return !table.insert(value).second; });
sample.erase(last, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
like above
Demo on coliru
#include <iostream>
#include <set>
using namespace std;
int main()
{
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(4);
p1.insert(2);
p1.insert(2);
for (auto iter = p1.begin(); iter != p1.end();)
{
p1.count(*iter) > 1 ? iter = p1.erase(iter) : iter++;
}
for (auto & iter : p1)
{
cout << iter << ", ";
}
return 0;
}

Is it possible to peek at the next element in a range-for loop?

Say I have this:
void test(std::vector<int>& my_ints) {
for (auto& my_int : my_ints) {
if (my_int == 5 && /* not the last value in the vector */) {
my_int += /* next value in the vector */;
}
}
}
Is there any valid syntax to replace the comments with?
PS! yes, i know, piece of cake with a regular for loop but I want to see if I can use range-for loops for this type of stuff.
Is it possible to peek at the next element
In general case - no.
Since objects in std::vector are stored contiguously, you could do *(&my_int + 1), but if you change the container later, the code might silently break. Don't do that!
And to check if the current element is the last one, you could use &my_int == &my_ints.back().
I can't think of a safe way to do what you want, with a ranged loop.
If you can bare an extra helper function, you could somehow generalize the algorithm you are using, though:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <class Container, class BinaryOp>
void apply_using_the_next(Container& cc, BinaryOp op)
{
if (std::cbegin(cc) == std::cend(cc))
return;
std::transform(std::begin(cc), std::prev(std::end(cc)),
std::next(std::cbegin(cc)),
std::begin(cc), op);
}
void test(std::vector<int>& v)
{
apply_using_the_next(v, [] (const int a, const int b) {
return a == 5 ? a + b : a;
});
}
int main()
{
std::vector<int> a{2, 5, 4, 3, 5, 5, 1};
test(a);
for (auto const i : a) // -> 2 9 4 3 10 6 1
std::cout << ' ' << i;
std::cout << '\n';
}
Live, here.
You can use iterator.
for (std::vector<int>::iterator it = my_ints.begin(); it < my_ints.end() - 1; ++it) {
if (*it == 5 /* no need to check as iterating until second last value && it != my_ints.end() - 1*/) {
*it += *(it+1);
}
}
Even if the vector is empty, the loop won't enter as it < my_ints.end() - 1 will return false, so it is safe.

C++ Performing mapping between vectors and unique numbers and vice versa

I need to create a dictionary data structure which maps vector to unique numbers and vice versa:
For example for mapping vectors to unique numbers, I can do the following:
vector ---------> unique number
(0,7,8) 0
(0,8,10) 1
(1,2,9) 2
(1,2,10) 3
(1,3,1) 4
Then I need to map back unique numbers to vectors, e.g. given below:
unique numbers --------> vector
0 (0,7,8)
1 (0,8,10)
2 (1,2,9)
3 (1,2,10)
4 (1,3,1)
I tried to do this mapping by creating a structure of integers and vectors -- however, this turned to be very inefficient. Is there some c++ data structure which can perform the forward and reverse mapping efficiently.
boost::bimap has the same functionality as what you're describing.
It is similar to std::map, but allows either element of the pair to be a key to the other element.
There is Boost.Bimap. This is a related question to Bimap Is there a Boost.Bimap alternative in c++11? .
In short, you can have two maps, one for each relationship (id -> vec, vec -> id).
[example as requested in a comment under the question]
Summarily, this makes the array index in the sorted ordering the "unique number" identifying a specific vector<int>, and seeks a specific vector<int> using std::lower_bound. Effectively, get_vec_id is just a convenience function if you find dealing in vector indices (with (size_t)-1 being a "not-found" sentinel value) more intuitive than repeatedly using lower_bound directly and dealing with iterators.
This is not very convenient when you have insert and/or erase of vector<int>s interspersed with lookups, because 1) earlier-retrieved indices are all invalidated, and 2) inserting and erasing in vectors is O(n). But, it's pretty good when the data's prepared first then a multitude of lookups are done.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
template <typename Data>
size_t get_vec_id(const Data& data, const typename Data::value_type& value)
{
auto it = std::lower_bound(data.begin(), data.end(), value);
if (it != data.end() && *it == value)
return it - data.begin();
else
return (size_t)-1;
}
int main()
{
std::vector<std::vector<int>> data =
{ { 0,7,8 },
{ 0,8,10 },
{ 1,2,9 },
{ 1,2,10 },
{ 1,3,1 } };
std::cout << get_vec_id(data, {0, 7}) << '\n';
std::cout << get_vec_id(data, {0, 7, 8}) << '\n';
std::cout << get_vec_id(data, {0, 7, 9}) << '\n';
std::cout << get_vec_id(data, {1, 2, 9}) << '\n';
std::cout << get_vec_id(data, {1, 2, 11}) << '\n';
std::cout << get_vec_id(data, {1, 3, 1}) << '\n';
std::cout << get_vec_id(data, {1, 4, 1}) << '\n';
// to map from a "vec_id" to a vector, use data[vec_id]...
}

C++ remove certain elements of vector

I am new to C++ and want to do vector element elimination.
My vectors are like:
<vector<vector>> objPoints;
<vector<vector>> delPoints;
<vector<vector>> objPoints2;
each objPoints has size 1000x3 and has all points. From objPoints i want to remove delPoints i.e. the (X,Y,Z) values that reside in each row.
Can anyone please tell me syntax?
I interpret your questions as follows: You have two vectors objPoints and delPoints which contain 1000 three-dimensional points. I would encode this as
std::vector<std::array<int,3> > objPoints;
where I assumed you have some raster such that you can desribe your points by int values (otherwise, for double entries, comparison is not that easy).
One benefit of using std::array<int,3> is that you automatically get a lexicographic ordering of the points (that means, specializations of std::less and std::equal_to which can directly be used without the further need to create some).
Algorithm:
First sort your arrays. There might be algorithms where this is not really necessary (see the other answer by #AshwaniDausodia), but the following assumes it. Further, in general by using sorted vectors one can obtain a better performance (at least in the big-O: for unsorted containers, it is roughly O(size1*size2), whereas it is lower for the following algorithm). The sorting first requires an effort of O(size1 log(size1)) + O(size2 log(size2))
Next, traverse both arrays at the same time and each time you find a common element delete it from one of the vectors. As you traverse sorted arrays, where you can always increase only the iterator pointing to the smaller element, this step takes O(size1+size2).
Implementation:
// deletes the elements from container c1 which are also present in c2
// requires sorted containers c1 and c2
//
template< class ContainerType1, class ContainerType2 >
void delete_common_elements(ContainerType1& c1, ContainerType2 const& c2 )
{
for(auto it1=c1.begin(), it2=c2.begin()
; it1!=c1.end() && it2!=c2.end(); )
{
if(*it1==*it2) // eventually change here if your points are not int's
// but are of floating-point type
{
it1 = c1.erase(it1); //it1 is increased here
}
else
{
*it1<*it2 ? ++it1 : ++it2;
}
}
}
DEMO
All together, this requires an effort of O(c1.size()) + O(c1.size() * log(c1.size()) (naturally assuming c1.size()>=c2.size()).
One can easily extend this to take an arbitrary comparison operator instead of the operator==.
If you definately have to use vectors, an easy (but inefficient) way would be to std::find the element in objPoints that you want to remove and then remove it with std::vector::erase.
You may consider read this Q&A on StackOverflow on how to erase elements from STL containers.
The key point is to use the erase-remove idiom to erase items from the vector, and use a lambda to express the erasing condition:
objPoints.erase(
std::remove_if(
objPoints.begin(),
objPoints.end(),
[&delPoints](const Point3D& point)
{
// Erasing condition:
// Is 'point' contained in the 'delPoints' vector?
auto it = std::find(delPoints.begin(), delPoints.end(), point);
return (it != delPoints.end());
}),
objPoints.end());
Full compilable code sample (live here):
#include <algorithm> // for std::find(), std::remove_if()
#include <array> // for std::array
#include <iostream> // for console output
#include <vector> // for std::vector
typedef std::array<int, 3> Point3D;
std::ostream& operator<<(std::ostream& os, const Point3D& point)
{
os << "{" << point[0] << ", "
<< point[1] << ", " << point[2] << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, const std::vector<Point3D>& v)
{
if (v.empty())
{
os << "{ <empty> }" << std::endl;
return os;
}
os << "{\n";
for (const auto& point : v)
{
os << " " << point << '\n';
}
os << "}" << std::endl;
return os;
}
int main()
{
std::vector<Point3D> objPoints{{1, 2, 3},
{4, 5, 6},
{11, 22, 33},
{44, 55, 66},
{77, 88, 99}};
std::vector<Point3D> delPoints{{10, 10, 10},
{11, 22, 33},
{44, 55, 66}};
std::cout << "objPoints =\n" << objPoints << std::endl;
std::cout << "delPoints =\n" << delPoints << std::endl;
objPoints.erase(
std::remove_if(
objPoints.begin(),
objPoints.end(),
[&delPoints](const Point3D& point)
{
// Erasing condition:
// Is 'point' contained in the 'delPoints' vector?
auto it = std::find(delPoints.begin(), delPoints.end(), point);
return (it != delPoints.end());
}),
objPoints.end());
std::cout << "\nAfter erasing, objPoints =\n";
std::cout << objPoints << std::endl;
}
Output:
objPoints =
{
{1, 2, 3}
{4, 5, 6}
{11, 22, 33}
{44, 55, 66}
{77, 88, 99}
}
delPoints =
{
{10, 10, 10}
{11, 22, 33}
{44, 55, 66}
}
After erasing, objPoints =
{
{1, 2, 3}
{4, 5, 6}
{77, 88, 99}
}
One obivious method would be:
for each point in delPoints
if point exists in objPoints
delete point from objPoints.
You can do it much more efficiently if you are allowed to sort the vectors. I will provide you with method and pseudo code then you can implement it on you own.
First sort objPoints and delpoints
i=0,j=0
while i < length(objPoints) and j < length(delPoints)
if objPoints[i] > delPoints[j] // Means delPoints[j] is not there in objPoints. If it would have, we would have found it.
j++
else if objPoints[i] < delPoints[j] // Means delPoints[j] is after objPoints[i] if it is there in objPoints
i++
else
erase objPoints[i] // Means we have found delPoints[j], so delete it.
For comaprison, first compare w.r.t x cordinate then y and then z. For sorting, you can use std::sort with same comparison function described in previous line. For deleting, you can use std::vector::erase.
Or you can implement your own fuctions.

How to store the item popped off from Vector in C++

I am making a program where i have to incorporate the use of vectors. But the problem is that i need to store the value of the popped off item from the vector. The vector's popback() doesn't really help with saving as it takes no arguments and has void return type. Help would be highly appreciated.
Try this example
std::vector<int> v = { 1, 2, 3, 4, 5 };
while ( !v.empty() )
{
int x = v.back();
v.pop_back();
std::cout << x << ' ';
}
std::cout << std::endl;
There are several ways to access elements of a vector as for example back(), front(), operator [], at(), *it where it is an iterator.