Correctly erasing an element from a vector - c++

If I have a table of vectors declared as
vector<int> table[9][9]
and I want to compare and delete the element if it already exists, would the deletion be:
for(int row = 0; row < 9; row++)//erases the current choice from the whole row
{
for(int h = 0; h < (int)table[row][k].size();h++)
{
if(table[row][k][h] == table[i][k][0])
{
table[row][k].erase(table[row][k].begin() + h);
}
}
}
I thought this would work, but I'm not 100% because I tried to delete every element using this technique and it didn't work, for those of you who want to see the code I used to delete all the elements, then it is:
for(int i = 0; i < 9; i++)
for(int k = 0; k < 9; k++)
for(int n = 0; n < table[i][k].size();n++)
table[i][k].erase(table[i][k].begin + n);
this method did not work, so I used clear instead.

I don't know what choice and k are, but to erase all values from a vector v that are equal to a particular value val use the "erase-remove idiom":
v.erase(
std::remove(v.begin(), v.end(), val),
v.end()
);
Hence, to do this same thing for all vectors in table:
for (auto &row : table) {
for (auto &v : row) {
v.erase(
std::remove(v.begin(), v.end(), val),
v.end()
);
}
}
If you have a more complicated condition than equality, use remove_if in place of remove. But in your case, the extra condition involving puzzle doesn't use the loop variable h, so I think you can test that before looking in the vector:
if (puzzle[row][k] == 0) {
// stuff with erase
}
In C++03 you can't use "range-based for loops" for (auto &row : table). So if you don't have C++11, or if you need the index for use in the puzzle test, then stick with for(int i = 0; i < 9; i++).

Related

How to convert an "int" variable to vector iterator in C++?

Imagine two nested loops each iterating with integer variables (let's say i and j). Inside these two loops, a function (fun) generates a vector (vec) using i and j as inputs. The generated vector has to be saved in a larger vector called total. I know that I can use push_back but I prefer to initialize my vector first (with static size). I tried to use insert but I don't know how can I convert int to vector<int>::iterator. I tried static_cast<vector<int>::iterator>(2*i +j) but it gives me this error:
no suitable constructor exists to convert from "int" to "__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int>>>"
using namespace std;
vector<double> total(M, 0); // Initilized with zeros
for (int i = 0; i < A; ++i)
{
for (int j = 0; j < B; ++j)
{
vector<double> vec = fun(i);
copy_n(vec.begin(), vec.size(), /* an iterator to where I want to save vec in total */);
}
}
The simplest method is vec.begin() + 2*i + j, but it'll work only for randomly accessible containers. For a generic solution you must use std::advance()
auto v = vec.begin();
std::advance(v, 2*i + j);
The return value of copy_n from the last iteration is the point where you should start inserting this iteration.
std::vector<double> total(M, 0); // Initilized with zeros
auto it = total.begin();
for (int i = 0; i < A; ++i)
{
for (int j = 0; j < B; ++j)
{
auto vec = fun(i);
it = std::copy_n(vec.begin(), vec.size(), it);
// or it = std::copy(vec.begin(), vec.end(), it);
}
}

How to erase or change element while iterating over vector in C++?

I was in the middle of creating a simple sieve of Erathostenes function when I stumbled upon one obstacle. In to order to accomplish the highest efficiency in this task I wanted to use only a vector. Here is the current code:
vector<int> sieveOfErathostenes(int N) {
vector <int> result(N, 1);
for(int i = 2; i < sqrt(N); i++)
if(result[i] == 1)
for(int j = 2*i; j < N; j += i)
result.at(j) = 0;
// :c
return result;
}
This vector returns 1 and 0 in the proper position but I can't figure out how to implement both erasing or changing an element's value in a single loop. When I use an iterator to erase an element as in erase set element while iterating/// I can't access the vector to change its value, and when I use a standard for loop to access the element I can't remove it. I have tried going from the end of the vector and counting non zero elements and giving some offset when erasing but no success.
TL DR: What I can't figure out is:
for(int i = 0; i < N; i++)
{
if(result[i] == 0) {
//remove at position i
} else {
result.at(i) = i;
}
}
Thank you in advance for your time :)
Instead of erasing elements in the middle of the vector, you should write the results from the beginning of the vector and eliminate the unused elements in the end of vector.
int finalSize = 0;
for(int i = 0; i < N; i++)
{
if(result[i] != 0) {
result[finalSize++] = i;
}
}
result.resize(finalSize);
If you still need to remove an element from a std::vector during traversal, keep in mind that erase returns an iterator following the last removed element:
std::vector<int> result = {1,1,1,0,1,1,1};
for(auto it = result.begin(); it != result.end(); )
{
if(*it==0)
it = result.erase(it);
else
it++;
}

Problems with vectors, how to remove the arrays in my vectors?

I have created a function that creates all the possible solutions for a game that I am creating... Maybe some of you know the bullcow game.
First I created a function that creates a combination of numbers of max four integers and the combination can't have any repeating number in it... like...
'1234' is a solution but not '1223' because the '2' is repeating in the number. In total there is 5040 numbers between '0123' and '9999' that haven't repeating numbers.
Here is my function:
std::vector <std::array<unsigned, 4>> HittaAllaLosningar(){
std::vector <std::array<unsigned, 4>> Losningar;
for (unsigned i = 0; i < 10; i++) {
for (unsigned j = 0; j < 10; j++) {
for (unsigned k = 0; k < 10; k++) {
for (unsigned l = 0; l < 10; l++) {
if (i != j && i != k && i != l && j != k && j != l && k != l) {
Losningar.push_back({i,j,k,l});
}
}
}
}
}
return Losningar;
}
Now let's say I have the number '1234' and that is not the solution I am trying to find, I want to remove the solution '1234' from the array since that isn't a solution... how do I do that? have been trying to find for hours and can't find it. I have tried vector.erase but I get errors about unsigned and stuff... also its worth to mention the guesses are in strings.
What I am trying to do is, to take a string that I get from my program and if it isn't a solution I want to remove it from the vector if it exists in the vector.
Here is the code that creates the guess:
std::string Gissning(){
int random = RandomGen();
int a = 0;
int b = 0;
int c = 0;
int d = 0;
for (unsigned i = random-1; i < random; i++) {
for (unsigned j = 0; j < 4; j++) {
if (j == 0) {
a = v[i][j];
}
if (j == 1) {
b = v[i][j];
}
if (j == 2) {
c = v[i][j];
}
if (j == 3) {
d = v[i][j];
}
}
std::cout << std::endl;
AntalTry++;
}
std::ostringstream test;
test << a << b << c << d;
funka = test.str();
return funka;
}
The randomgen function is just a function so I can get a random number and then I go in the loop so I can take the element of the vector and then I get the integers of the array.
Thank you very much for taking your time to help me, I am very grateful!
You need to find the position of the element to erase.
std::array<unsigned, 4> needle{1, 2, 3, 4};
auto it = std::find(Losningar.begin(), Losningar.end(), needle);
if (it != Losningar.end()) { Losningar.erase(it); }
If you want to remove all the values that match, or you don't like checking against end, you can use std::remove and the two iterator overload of erase. This is known as the "erase-remove" idiom.
std::array<unsigned, 4> needle{1, 2, 3, 4};
Losningar.erase(std::remove(Losningar.begin(), Losningar.end(), needle), Losningar.end());
To erase from a vector you just need to use erase and give it an iterator, like so:
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
auto it = vec.begin(); //Get an iterator to first elements
it++; //Increment iterator, it now points at second element
it = vec.erase(it); // This erases the {4,3,2,1} array
After you erase the element, it is invalid because the element it was pointing to has been deleted. Ti continue to use the iterator you can take the return value from the erase function, a valid iterator to the next element after the one erased, in this the case end iterator.
It is however not very efficient to remove elements in the middle of a vector, due to how it works internally. If it's not important in what order the different solution are stored, a small trick can simplify and make your code faster. Let's say we have this.
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
vec.push_back({3,2,1,4});
To remove the middle one we then do
vec[1] = vec.back(); // Replace the value we want to delete
// with the value in the last element of the vector.
vec.pop_back(); //Remove the last element
This is quite simple if you have ready other functions:
using TestNumber = std::array<unsigned, 4>;
struct TestResult {
int bulls;
int cows;
}
// function which is used to calculate bulls and cows for given secred and guess
TestResult TestSecretGuess(const TestNumber& secret,
const TestNumber& guess)
{
// do it your self
… … …
return result;
}
void RemoveNotMatchingSolutions(const TestNumber& guess, TestResult result)
{
auto iter =
std::remove_if(possibleSolutions.begin(),
possibleSolutions.end(),
[&guess, result](const TestNumber& possibility)
{
return result == TestSecretGuess(possibility, guess);
});
possibleSolutions.erase(iter, possibleSolutions.end());
}
Disclaimer: it is possible to improve performance (you do not care about order of elements).

c++ iterate through all neighbor permutations

I have a vector of N objects, and I would like to iterate through all neighbor permutations of this vector. What I call a neighbor permutation is a permutation where only two elements of the original vector would be changed :
if I have a vector with 'a','b','c','d' then :
'b','a','c','d' //is good
'a','c','b','d' //is good
'b','a','d','c' //is not good (2 permutations)
If I use std::next_permutation(myVector.begin(), myVector.end() then I will get all the possible permutations, not only the "neighbor" ones...
Do you have any idea how that could be achieved ?
Initially, I thought I would filter the permutations that have a hamming distance greater than 2.
However, if you really only need to generate all the vectors resulting by swapping one pair, it would be more efficient if you do like this:
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++)
// swap i and j
Depending on whether you need to collect all the results or not, you should make a copy or the vector before the swap, or swap again i and j after you processed the current permutation.
Collect all the results:
std::vector< std::vector<T> > neighbor_permutations;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
std::vector<T> perm(v);
std::swap(perm[i], perm[j]);
neighbor_permutations.push_back(perm);
}
}
Faster version - do not collect results:
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
std::swap(v[i], v[j]);
process_permutation(v);
std::swap(v[i], v[j]);
}
}
Perhaps it's a good idea to divide this into two parts:
How to generate the "neighbor permutations"
How to iterate over them
Regarding the first, it's easy to write a function:
std::vector<T> make_neighbor_permutation(
const std::vector<T> &orig, std::size_t i, std::size_t j);
which swaps i and j. I did not understand from your question if there's an additional constraint that j = i + 1, in which case you could drop a parameter.
Armed with this function, you now need an iterator that iterates over all legal combinations of i and j (again, I'm not sure of the interpretation of your question. It might be that there are n - 1 values).
This is very easy to do using boost::iterator_facade. You simply need to define an iterator that takes in the constructor your original iterator, and sets i (and possibly j) to initial values. As it is incremented, it needs to update the index (or indices). The dereference method needs to call the above function.
Another way to get it, just a try.
int main()
{
std::vector<char> vec={'b','a','c','d'};
std::vector<int> vec_in={1,1,0,0};
do{
auto it =std::find(vec_in.begin(),vec_in.end(),1);
if( *(it++) ==1)
{
for(auto &x : vec)
{
std::cout<<x<<" ";
}
std::cout<<"\n";
}
} while(std::next_permutation(vec_in.begin(),vec_in.end()),
std::next_permutation(vec.begin(),vec.end()) );
}

why vector does not updates in loop?

I want to update vector 'v' so that I can iterate from count 0-100.
I know this is not allowed, but what if I want to do this only?
Is there any way?
int main() {
// your code goes here
vector<int> v;
v.push_back(1);
int count = 0;
for(int elem: v){
if(count<100)
v.push_back(count);
count++;
}
for(int elem: v)
cout << elem << endl;
return 0;
}
The output is:
1
0
As you can see from the definition of the range-based for loop, the end_expr does not update between iterations. Therefore you only have one iteration. push_back invalidates v.end() (which is what end_expr is as described in the linked page), so what you have is actually undefined behaviour.
The arguably simplest way to fill vector with 0..100 would be:
vector<int> v(101);
std::iota(v.begin(), v.end(), 0);
You should use this code instead
int count = 0;
while (v.size() < 100) {
v.push_back(count++)
}
Modifying vector while iterate through it is not allowed
Best efective way for this operation
vector<int> v;
v.resize(100);
for(unsigned int i = 0; i < v.size(); i++)
{
v[i] = i;
}
same as above.
using your code :
for(int elem: v){
if(count<100)
v.push_back(count);
count++;
}
is like using this :
int i = v.size();
for(int j = 0; j < i; j++){
v.push_back(j);
}
I don't really know why... v.size() might be keep in memory for optimization and data protection
Edit after OP comment :
Try this
int i = v.size();
for(int j = 0; j < i; j++){
if(j<100)
i = v.size();
v.push_back(count);
}
A range-based for loop produces code similar to this:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,__end = end_expr; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
As you can see the range will not be updated as you're iterating over your container.
Additionally you're most likely ending up with undefined behaviour because as you're pushing back values to your vector these iterators will be invalidated in case of a resize.
See #user2079303 for a better way to fill your vector.