C++: Store mapping between old int handles and new ones - c++

I have an array with struct elements. I need to remove some elements from the array and store mapping between old values ​​and new ones.
I.e, fill std::map, the key of which is the old index of the element from the array and Its value is the new index from the array. (Because when values ​​are removed from the vector, it is shifted to the left.)
I will show what I need with an example:
0 1 2 3 4 5 6
arr0 = {a, b, c, d, e, f, g}
0 1 2 3 4 5
arr1 = {a, b, c, e, f, g} //after delete d
map[0]=0 // a
map[1]=1 // b
map[2]=2 // c
map[4]=3 // e
map[5]=4 // f
map[6]=5 // g
Help me to implement this.
I have an array from structures:
struct HalfEdgeHandle { int64_t index = -1; };
std::vector<HalfEdgeHandle> halfEdges = {};
I need to remove the elements of the array which halfEdges[i].index == -1

As long as I have understood your question, this should be the solution:
struct HalfEdgeHandle {};
std::vector<HalfEdgeHandle> halfEdges = {};
// Here store your data into the vector
std::map<int, int> map;
std::vector<HalfEdgeHandle> copy;
int j = 0;
for(int i = 0; i < halfEdges.size(); i++)
{
if(halfEdges[i].index != -1)
{
copy.append(halfEdges[i]);
map[i] = j++;
}
}
copy should be the std::vector without any element which has index == -1. map will look like as you described.
Let me point out two things:
Consider changing the map and copy variable names into something that makes more sense in your code
Consider changing how you store the previous indexes and the new ones. I would swap the key-value pair, so you have continuous indexes. If you do this, you can use std::vector instead of std::map (I usually tend to avoid using std::map when not mandatory).

Related

How to create a new vector where each element must be calculated from many vectors?

I have a join_function which takes two elements and saves the result by updating the calling element. For example, if I have three initial elements A, B and C and one later element D, I can use the following code.
for (auto it = begin, et = end; it!=et; ++it)
{
later_element N = *it;
D.join_function(N);
}
The above code will join A and D, saves the result to D. Then joins B and D and saves the result to D and so on. The for loop iterates over all later elements.
Now, my problem is how to handle the same with vectors. I do not know if there will be 3 such later element vectors or more or less but the for loop is able to iterate over them. The size of vectors can be power of 2: 1 or 2 or 4 or 8 and so on. For example, if A is of size 2, B is of size 4, C is of size 1 and D is of size 2, the new result vector (say) E will have size 16.
E[0] will be created by joining A[0]D[0], B[0]D[0] and C[0]D[0]. E[1] will be A[0]D[0], B[1]D[0] and C[0]D[0]. E[2] will be A[0]D[0], B[2]D[0] and C[0]D[0] and so on till B is covered. Then similarly A will be covered. Of course the order is not fixed and first A and then B and then C can be covered. Once all later elements are covered using D[0], same must be repeated for D[1] and so on for all D elements. I call D as initial element. So its loop is obvious to me but the covering of later element vectors is not clear. The below code is clear to me when initial_element is the D vector.
for (long i=0; i< initial_element.size(); ++i)
{
for (auto it = begin, et = end; it!=et; ++it)
{
later_vector later = *it;
}
}
You can store intermediate results, and loop over one input vector at a time.
using Elems = std::vector</* Your element type*/>;
Elems combine(const Elems & acc, const Elems & next) {
Elems result;
for (auto a : acc) {
for (auto n : next) {
result.push_back(a.join(n));
}
}
return result;
}
Then to combine them all is std::accumulate
int main() {
std::vector<Elems> inputs = { A, B, C, D }; // or whatever
Elems E = std::accumulate(inputs.rbegin() + 1, inputs.rend(), inputs.back(), combine);
}

std vector size keep ground Although i insert in the same indexs

Something wired i see here with std vector
I have
variable that its value is dynamically changes but always under 20
dynamicSizeToInsert in the example.
why the vector size keeps growing ?
std::vector<int> v;
//sometimes its 5 sometimes it is 10 sometimes it is N < 20
int dynamicSizeToInsert = 5
int c = 0;
for(std::vector<int>::size_type i = 0; i != 100; i++) {
if(c == dynamicSizeToInsert )
{
c = 0;
}
v.insert(v.begin() + c, c);
c++;
printf("%d",v.size()) //THIS THINK KEEP growing although i only using vector indexes 0 to 4 allways
}
i want to keep my vector side 5 elements big
and that new value will run over other value in the same index .
std::vector::insert, as the name suggests, inserts elements at the specified position.
When c == dynamicSizeToInsert, c is set to 0. So now, v.size() == 5. Now this lines executes:
v.insert(v.begin() + c, c);
This will insert 0 at posistion v.begin() + 0, which is position 0 and it will offset every other element (it will not replace the element at position 0), and so the vector keeps growing.
Instead of using insert, use operator[]:
//So that 'v' is the right size
v.resize(dynamicSizeToInsert);
for(std::vector<int>::size_type i = 0; i != 100; i++) {
if(c == dynamicSizeToInsert )
{
c = 0;
}
v[i] = c; //Sets current index to 'c'
c++;
}
insert doesn't replace element, rather it inserts element at given location and shifts all the right elements to one position right. That's why your vector size is growing.
If you want to replace an existing index then you can use operator[]. However, keep in mind that the index must be between 0 - size() - 1 in order to use operator[].
std::vector::insert inserts a new member into the array at the index you specify, and moving the other elements forward or even reallocating the array once it reaches capacity(a relatively expensive operation)
The vector is extended by inserting new elements before the element at
the specified position, effectively increasing the container size by
the number of elements inserted.
This causes an automatic reallocation of the allocated storage space
if -and only if- the new vector size surpasses the current vector
capacity.
(http://www.cplusplus.com/reference/vector/vector/insert/)
As quoted above, the vector is extended with every insert operation.
to get the behaviour you want you need to use the [] operator like so:
v[i] = some_new_value;
this way a new element is never added, its only the value of the ith element that is changed.
const int dynamicSizeToInsert = 5;
std::vector<int> v(dynamicSizeToInsert);
int c = 0;
for(std::vector<int>::size_type i = 0; i !=100; i++)
{
v.at(i%dynamicSizeToInsert) = (dynamicSizeToInsert == c?c = 0,c ++: c ++);
printf("%d",v.size());
}

Problems using 3-dimensional vector

How can I work with a 3 dimensional vector in C++?
vector<vector<vector<int> > > vec (1,vector<vector<int> >(1,vector <int>(1,12)));
When I try something like this
cout << vec[0][0][0]; vec[0][0][1] = 13;
everything works just fine.
The problem is that I can only change the last elements. If I try accessing the first and second element, like this
vec[0][1][0] = 13;
or this
vec.push_back(vector<vector<int > >());
vec[0].push_back(vector<int>());
v[1][0].push_back(13);
my program crashes.
How can I add and access elements in a 3d vector?
I would never do vector<vector<vector<int> > > as in this way you have many allocations what could be expensive. I would simply use vector<int> with smart indexing (e.g.: see below). If you will work with double based matrices, in this way intel MKL or any other BLAS library easily could be used.
Its price is increased complexity when matrix sizes are changed, but you could win many in performance.
Useful link: C++ FAQ.
static int const M = 16;
static int const N = 16;
static int const P = 16;
inline int& set_elem(vector<int>& m_, size_t i_, size_t j_, size_t k_)
{
// you could check indexes here e.g.: assert in debug mode
return m_[i_*N*P + j_*P + k_];
}
inline const int& get_elem(const vector<int>& m_, size_t i_, size_t j_, size_t k_)
{
// you could check indexes here e.g.: assert in debug mode
return m_[i_*N*P + j_*P + k_];
}
vector<int> matrix(M*N*P, 0);
set_elem(matrix, 0, 0, 1) = 5;
vector<vector<vector<int> > > vec (1,vector<vector<int> >(1,vector <int>(1,12)));
cout << vec[0][0][0]; vec[0][0][1] = 13;
evething is OK.
You are mistaken. Everything is not OK. The vector vec[0][0] has only one element and thus vec[0][0][1] is out of bounds and therefore the assignment has undefined behaviour. You have the same problem with vec[0][1][0] = 13; and v[1][0].push_back(13)
You can fix that by accessing only indices that exist in your vectors. If you want more than one element, then either construct the vectors with more elements initially, or push them after construction.
At the begining I have 1x1x1 vector. So how can I push elements. using push_back() ? For example I have 1x1x1 and I want to add v[1][1][0] = 2 ?
If you for some reason want to start with 1x1x1 vector of vectors of vectors of ints and want to access v[1][1][0], here is example code to add the v[1][1][0] element with minimal changes to the original vector:
// vector of ints that contains one element, 2
// this will vector eventually be the v[1][1] and the integer element will be v[1][1][0]
// since we initialize the integer as 2, there's no need to assign it later though
vector<int> vi(1, 2);
// vector of vectors that contains one default constructed vector
// vvi will eventually be the v[1] element and the default constructed vector will be v[1][0]
vector<vector<int>> vvi(1);
// push vi into vvi, making it vvi[1] and eventually v[1][1]
vvi.push_back(vi);
// push vvi into v, making it v[1]
v.push_back(vvi);
What you have,
vector<vector<vector<int> > > vec (1,vector<vector<int> >(1,vector <int>(1,12)));
creates 1 x 1 x 1 matrix with the value of the only element set to 12.
To create something that is analogous to a M x N x P matrix, you need to use:
vector<vector<vector<int> > > vec (M,vector<vector<int> >(N,vector <int>(P,x)));
That will create an M x N x P matrix with the value of each element set to x.

Not getting the input values when printing vector of pairs

I want to add a pair to a vector of pairs.
When I print the vector elements, I don't get the integers I input.
Please help.
#include<iostream>
#include<vector>
#include<utility>
using namespace std;
int main()
{
vector<vector<unsigned long int> >matrix;
vector<pair<int,int> >pmat;
int L;
cin>>L;
int n1, n2;
pmat.resize(L);
for(int k = 0; k<L; k++)
{
cin>>n1>>n2;
pair<int,int> p = make_pair(n1,n2);
cout<<p.first<<p.second<<endl;
pmat.push_back(p);
}
for(int k = 0; k<L; k++)
{
cout<<pmat[k].first<<','<<pmat[k].second<<' ';
}
cout<<endl;
return 0;
}
Method 1:
Delete this line:
pmat.resize(L);
You don't need to resize it in the first place as you do push_back() when adding afterwards.
Method 2:
Change the following line
pmat.push_back(p);
to
pmat[k] = p;
You can do resize() in the first place, but after this, you should not use push_back() when adding, just use pmat[k] = p.
PS: you should not mix these two ways up. Always use one of them consistently.
Since you're using pmat.resize(L) and L times pmat.push_back(...), you're ending up having stored 2 * L entries in your vector. However you're printing just the first half, index 0 to L - 1. The values you want are stored from index L to 2 * L - 1.
Just change pmat.resize(L) to pmat.reserve(L).
Alternatively, you can use the resize(L), but to end up with L entries, you need to store each input pair to pmat[k], hence you write pmat[k] = p;.
As a rule of thumb, I recommend using the reserve + push_back approach if you know how many elements you're going to add. The reason is, that resize initializes the elements, while reserving just asserts that there will be enough space and no reallocation will be necessary with any following push_back.
You don't want to add more pairs after you allocated them. You can now directly access them.
Just use pmat[k] = p; instead of pmat.push_back(p);
If you print the size of the vector after reading the values, you will notice a small problem with your program:
./test
2
1 2
12
3 4
34
Size of the vector: 4
0,0 0,0
Huh? Even though I only entered 2 pairs, the size of the vector is 4. How did this happen?
If you look at the documentation for resize, it says
Resizes the container to contain count elements.
So even before you read any values, your vector will already contain 2 elements! Those will be default-constructed and therefore be 0. When you then push_pack the elements you read in, those will land at the indices 2 and 3 in the vector, so the end vector has twice as much elements as you wanted (4 in this case). You only print out the first half, which are the zero values.
The solution is to use reserve instead of resize, which doesn't create the elements but only reserves space for them, or just delete the call to resize. Using reserve is more efficient though, because then the vector will only need to allocate memory once.
pmat.resize(L);
if vector in empty its going to initialize a vector pmat with size L then assign default values to vector so now pmat size is L with default values
for(int k = 0; k<L; k++)
{
cin>>n1>>n2;
pair<int,int> p = make_pair(n1,n2);
cout<<p.first<<p.second<<endl;
pmat.push_back(p);
}
then u r pushing values to pmat L times so the final size is 2*L
for(int k = 0; k<L; k++)
{
cout<<pmat[k].first<<','<<pmat[k].second<<' ';
}
here u r going to read from 0 to L-1 , it contains default values you can see your values from L-1 to 2L-1.
so finally what i want say is use reserve instead of resize
or
pmat.resize(L); comment this line

How to sort both data member arrays of a class in code shown

I have a simple C++ code written to understand sort function usage on user defined class data types to sort data members of a class.
But this only sorts array of variable b in the class. Because, the earlier sorted array of variable a, is also disturbed whiel sorting b.
#include <iostream>
#include <cstring>
using namespace std;
class Entry
{
public:
int a, b;
};
bool compare1(Entry e1, Entry e2)
{
if (e1. a > e2. a) return false;
return true;
}
bool compare2( Entry e1, Entry e2)
{
if (e1. b > e2. b) return false;
return true;
}
int main()
{
int i;
vector<Entry> array(4);
array[0]. a =5 , array[0]. b =8 ;
array[1]. a =10 , array[1]. b =4 ;
array[2]. a =3 , array[2]. b =2 ;
array[3]. a =1 , array[3]. b =12 ;
sort(array.begin(), array.end(), compare1);
sort(array.begin(), array.end(), compare2);
cout << "sorted:" << endl;
for (i = 0; i< 4; i++)
cout << array[i]. a << " " << array[i].b << endl;
}
The output I get is as follows:
sorted:
3 2
10 4
5 8
1 12
How to sort both data member arrays - a,b?
It depends on how you want your elements to be sorted:
Sort as pairs, keyed on a: (1,12), (3,2), (5,8), (10,4)
Sort as pairs, keyed on b: (3,2), (10,4), ...
Sort as pairs lexicographically: same as sorting on a, since there are no repeated values for a.
In case (1) you use compare1, in case (2) you use compare2. (For case (3) you would have to write another predicate, or just use std::pair<int,int>.)
Case 4: If you want the values of a and b sorted separately and destroy the pairing, then you need to put the values into separate vectors of ints and sort those individually:
std::vector<int> avals(array.size()), bvals(array.size());
for (size_t i = 0; i != array.size(); ++i)
{
avals[i] = array[i].a;
bvals[i] = array[i].b;
}
std::sort(avals.begin(), avals.end());
std::sort(bvals.begin(), bvals.end());
There is no way around this. A container of Entry objects can only move elements around as a whole.
I think you are confusing what sort does. It does not hort the members that you use in the comparison function, but rather the whole objects. In your case that means that the because you initialized one object with value pair (5,8), there will always be an element in the vector that is (5,8).
Sorting the array by the first member means that it move to the second to last position (5 being the second to last biggest first element), and sorting by the second element will move the object to, well in this case also the second to last position, but that will only move the object in the container, it will always be (5,8).
If you want both to impact the comparison, include both in the check (i.e. compare) function. Else, it's either one or the other. If you need to have different "views", you need a smarter container (such as boost::multi_index)