Nested iterators access - c++

I have a question about iterators.The question is:" How can I access ( if it's a nested iterator ) the element in row, that is higher or below.Here's an example what I mean:
for( auto i = graphMatrix.begin();i != graphMatrix.end();i++ )
{
for( auto j = i->begin();j != i->end();j++ )
{
if( *j == 'O' )
{
// here we must analyze an element which is a row higher or lower
}
}
}
Next thing is what I wanted to do ( but it's with vector ):
for( int i = graphMatrix.size();i < graphMatrix.size();i++ )
{
for( int j = graphMatrix.size();j < graphMatrix.size();j++ )
{
if( graphMatrix[i][j] == 'O' )
{
graphMatrix[j][i] == 'X';
}
}
}
I know that vector has fast size function, but to generalize the code, in my mind, it's better to use iterators ( as my mentor said ).So how can I do the same stuff with iterators as with vectors?

Since iterators are non-numeric, they are not well-suited to this problem.
You can write complex, confusing and possibly costly code with std::distance and std::advance, performing "pointer arithmetic" on your iterators... or you can stick with your numeric loop counters approach, which is precisely what I'd do. Especially seeing as you're using vectors, which have constant-time (and, let's face it, immediate) access to arbitrary elements in arbitrary positions.
If you're wondering why, in this case, iterators are suddenly not the "better" mechanism for iteration that you've been taught they are: it's because one must use the correct tool for the job, and no technology is the correct tool for all jobs.

to get the position of you vector from the iterator with std::distance:
for( auto i = graphMatrix.begin();i != graphMatrix.end();i++ )
{
for( auto j = i->begin();j != i->end();j++ )
{
int x = std::distance(graphMatrix.begin(),i);
int y = std::distance(i->begin(),j);
graphMatrix[x][y] = 'x';
}
}

Related

C++ trying multiple conditions in if statement with loop

I'm currently trying to create a sudoku solver in C++, but I have run into a slight problem. Instead of starting out with a 9x9 sudoku, I've started with a 4x4 one. For every square that can contain a number I am trying to get the possible numbers that square can hold into an array, e.g. if the possibilities in square 3 are 1 and 4,
for ( int i; i < 4; i++ ) {
cout << candidates[3][i];
}
would give me 1004. It is easily accessible when I need to code hard solving methods or a brute force solving method.
Here is the problem: I need to check whether a number occurs in any row, column or (2x2 or 3x3) box, and if it does not, add it to the candidates array. Here's what I thought of:
for ( int i = 0; i < 16; i++ ) {
for ( int j = 1; j < 5; j++ ) {
if ( for ( int k = 0; k < 4; k++ ) { allRows[getRow(i)][k] != j || allCols[getCol(i)] [k] != j || allBoxs[getBox(i)][k] != j}) {
candidates[i][j-1] = j;
}
}
}
The arrays allRows, allCols, allBoxs all contain the sudoku, only in such an order that they are easily accessible when they are needed. The functions getRow(), getCol() and getBox() return the number of the row, column or box (respectively, of course) the input number is in.
I tried to make it loop though everything in the same row, column or box as the number, to get all twelve checked by the if, and if they all passed, then I would add the number to the candidates array.
It came to me as no surprise that it returned an error when I tried to compile this. But I really don't want to write out twelve AND conditions in the if statement, or 27 when I upgrade to 9x9 sudoku, because:
I don't learn anything and
Where's the fun in that?
Can anyone help me / suggest another idea to do this without typing everything out?
I apologize if my inability to be concise hinders an answer to this question, I was only trying to provide all the details I thought maybe were necessary...
Condition of if should be an expression convertible to bool. it is not the case of for-statement.
You might do instead (assuming I correctly understood your condition):
for ( int i = 0; i < 16; i++ ) {
for ( int j = 1; j < 5; j++ ) {
bool b = false;
for ( int k = 0; k < 4; k++ ) {
if (allRows[getRow(i)][k] != j || allCols[getCol(i)][k] != j || allBoxs[getBox(i)][k] != j) {
b = true;
break;
}
}
if (b) {
candidates[i][j-1] = j;
}
}
}
or with helper function
template <typename Range, typename T>
bool contains(const Range& range, constT& value)
{
using std::begin;
using std::end;
return std::find(begin(range), end(range), value) != end(range);
}
// ...
for ( int i = 0; i < 16; i++ ) {
for ( int j = 1; j < 5; j++ ) {
if (!contains(allRows[getRow(i)], j)
|| !contains(allCols[getCol(i)], j)
|| !contains(allBoxs[getBox(i)], j)) {
candidates[i][j-1] = j;
}
}
}
Like you already noticed, adding an for-statement inside of the condition of the if doesn't work. There are several reasons for it, however, let me point out a few that cause confusion:
What if the for-loop wouldn't iterate? Would this result in true or false?
What if you have multiple iterations? Would we && or || the boolean values into it? And how about short cutting of those operators?
Long story short: Even if this would be considered to ever add to the standard, I expect it to be blocked thanks to the many edge cases.
So what does this mean? Is this impossible? Off course not, it's C++. Like already mentioned in the answer of #Jarod42 you can calculate a boolean and than do the if-statement. Or like both of us mentioned (me in the comments), you could move this into a function.
Personally, I've stepped away from remembering state about my for-loop like with this boolean. The main reason: This is hard to read. Every single time you read that code, you need to check what's actually happening.
Hence, I suggest to move this to a function. A function has a clear name and could even be tested separately to ensure it's behavior is correct.
So in this case, I would write something like:
template<typename T1, typename T2, typename T3>
auto checkForExistanceOf(int shouldExist, int locator, T1 &&allRows, T2 &&allCols, T3 &&allBoxs)
{
for ( int k = 0; k < 4; k++ )
{
if (allRows[getRow(locator)][k] != shouldExist)
return true;
if (allCols[getCol(locator)] [k] != shouldExist)
return true;
if (allBoxs[getBox(locator)][k] != shouldExist)
return true;
}
return false;
}
The code on caller side than becomes:
for ( int i = 0; i < 16; i++ )
{
for ( int j = 1; j < 5; j++ )
{
if (checkForExistanceOf(j, i, allRows, allCols, allBoxs))
{
candidates[i][j-1] = j;
}
}
}
For sure, my names ain't that good, as I don't know the exact purpose, nor would I suggest using a template as you know the actual types, though, this is the idea behind it.

Segmentation fault when assigning the return vector of a function to another vector

I'm having a problem with one of my homework assignments in which we need to detect duplicate strings in a vector of strings using a hash table. My code builds and compiles fine but I get a Segmentation fault when I try to assign the return vector from the duplicate detection algorithm to the duplicates vector. I've tried to figure out why this is happening but can't find a solution. I've attached my code below.
Function to find duplicates using hash table ##
std::vector<std::string>find_duplicates_with_hashtable(std::vector<std::string> & strings) {
std::vector<std::string> dups;
typedef std::unordered_map<std::string, std::string> hashtable;
hashtable table;
for (std::vector<std::string>::iterator i = strings.begin(); i < strings.end(); i++) {
std::unordered_map<std::string, std::string>::const_iterator it = table.find(*i);
if (it != table.end() && (std::find(dups.begin(), dups.end(), *i)) == dups.end()) {
dups = find_duplicates_with_sorting(dups); // line causing the problem
}
table.emplace(*i, *i);
}
return dups;
}
Function used to check if any elements in the given vector are present in the duplicates vector
std::vector<std::string> find_duplicates_with_sorting(std::vector<std::string> & strings) {
std::vector<std::string> dups;
std::sort(strings.begin(), strings.end());
for( unsigned int i = 0; i < strings.size() - 1; ++i ) {
if( strings[i].compare(strings[i+1]) == 0 ) {
std::string found_dup = strings[i];
if( dups.size() == 0 ) {
dups.push_back(found_dup);
}
else
{
std::string last_found_dup = dups[ dups.size() - 1 ];
if( last_found_dup.compare(found_dup) != 0 ) { // Not a dup of a dup
dups.push_back(found_dup);
}
}
}
}
return dups;
}
This is the context in which the hash table function is being called
TEST(BaseHash, SuperShortVector)
{
std::vector<std::string> dups_found;
auto & search_vector = super_short_vector;
auto & known_dups_vector = super_short_vector_dups;
dups_found = find_duplicates_with_hashtable(search_vector);
std::sort(dups_found.begin(), dups_found.end());
std::sort(known_dups_vector.begin(), known_dups_vector.end());
}
The line causing the problem is marked by a comment in the 'find_duplicates_with_hashtable' function
Also, since this is a homework assignment, I would greatly appreciate if someone could explain what I did wrong and just give me a general direction I could work towards in order to fix the problem since just copy-pasting code wouldn't help me learn
Sorry if the code is horrible. I'm having trouble understanding how to use hash tables.
Thank you :)
The segfault is happening here:
for( unsigned int i = 0; i < strings.size() - 1; ++i ) {
if( strings[i].compare(strings[i+1]) == 0 ) {
The issue is that you are comparing an unsigned value, i, with the unsigned value returned from strings.size() - 1. When strings.size() is 0, this part i < strings.size() - 1 will be checking if i is less than the greatest integer value, which will (basically) always be true.
This causes strings[i+1] to segfault when strings is length 0 or 1.
This can be fixed in many ways, but for( int i = 0; i < (int)strings.size() - 1; ++i ) { would be a quick and dirty way to fix it.

Erasing indices of std::vector inside a for loop based on vector size

I've created a function to filter out the elements I don't like in a std::vector, in this case a vector of opencv contours. The code below looks like it would work, however it does not and I suspect it is because the indices are changed whenever I erase the indices, however I continue to the next i value iteration.
void FilterContours( std::vector<std::vector<cv::Point>> contours )
{
for ( int i = 0; i < contours.size(); i++ ) {
//Remove contours smaller than 5 from vector - example
if ( contours[i].size() < 5 ) {
contours.erase(contours.begin() + i);
continue;
}
//Other filtering...
}
return;
}
So the question is, would this work as intended (I don't think it does), and if not, how do I make it work as intended? Should I add a i -= 1 after the erase to maintain the correct index position?
Each time you erase() an element from a container, its size() decrements, and the indexes of the remaining elements are decremented as well. But you are incrementing your loop counter unconditionally, so every time you erase an element, you skip the next element that had followed it!
Also, you are passing your vector by-value, so you are operating on a copy of the vector, and the caller will not see any changes in the original vector.
The correct approach would be to either:
increment your index variable inside of the loop body only when an element is NOT erased. Leave the variable as-is when you DO erase an element:
void FilterContours( std::vector<std::vector<cv::Point>> &contours )
{
int i = 0;
while ( i < contours.size() ) {
if ( contours[i].size() < 5 ) {
contours.erase(contours.begin() + i);
continue;
}
//Other filtering...
++i;
}
}
use iterators instead of indexes:
void FilterContours( std::vector<std::vector<cv::Point>> &contours )
{
auto it = contours.begin();
while ( it != contours.end() ) {
if ( it->size() < 5 ) {
it = contours.erase(it);
continue;
}
//Other filtering...
++it;
}
}
use the erase-remove idiom:
void FilterContours( std::vector<std::vector<cv::Point>> &contours )
{
contours.erase(
std:::remove_if(
contours.begin(),
contours.end(),
[](const std::vector<cv::Point> &v)
{
if (v.size() < 5) return true;
//Other filtering...
return false;
}
),
contours.end()
);
}
Use the erase-remove idiom:
contours.erase(
std::remove_if(contours.begin(), contours.end(), [](const std::vector<cv::Point>& v){
return v.size() < 5;
}),
contours.end()
);
In general, when you iterate for removing, it is always better to iterate backwards:
for ( int i = contours.size()-1; i >=0; --i)
This will work but it results in slow code, because at each removal, the elements behind the removal will be copied/shifted back. For this reason, it is better, faster and more readable to use the dedicated idioms provided by the standard algorithm library, which are usually very optimized. In this case you have the erase/remove_if combination:
contours.erase(std::remove_if(contours.begin(), contours.end(), [](const auto& elem) { return elem.size() < 5; }), contours.end() );
A big advantage here is that std::remove_if() acts in a smarter way than the intuitive loop: it first "marks" the elements to remove, and then it compacts the remaining elements together. This process is O(N), while the (intuitive) loop is O(N^2), a huge difference for big vectors.
p.s.: the signature of your FilterContours function to take the vector by reference:
void FilterContours( std::vector<std::vector<cv::Point>>& contours ) // <-- by reference
Your FilterContours should take a reference, otherwise it won't have any impact on the caller.
void FilterContours(std::vector<std::vector<cv::Point>>& contours)
{
for (auto it = contours.begin(); it != contours.end(); )
{
if (it->size() < 5)
it = contours.erase(it);
else
++it;
}
}
Edit:
If you want to do it in the reverse order you could do:
void FilterContours_reverse(std::vector<std::vector<cv::Point>>& contours)
{
for (auto it = contours.rbegin(); it != contours.rend(); )
{
if (it->size() < 5)
contours.erase(std::next(it++).base());
else
++it;
}
}

Find if vector is subvector c++

Assume that I have:
std::vector<string> group;
std::vector<string> subGroup;
Some properties about those two vectors:
1) All elements are unique.
2) They're not sorted, and sorting is not an option.
I need to check if group contains subgroup. If it does, than I need to return true, if it doesn't return false.
Examples:
group = {"A","B","C","D"}, subGroup = {"A","D","E"} -> answer = false
group = {"A","E","C","D"}, subGroup = {"A","D","E"} -> answer = true
My current implementation is:
int cont=0;
if(subGroup.size() > group.size())
return false;
else{
for(int i=0; i<subGroup.size(); i++){
for(int j=0; j<group.size(); j++){
if(subGroup[i] == group[j]{
cont++;
}
}
}
if (cont == subGroup.size())
return true;
return false;
}
I checked on this post here locate sub-vector<string> in another vector<string> , but I'm not supposed to use C++11 features and also this answer does not solve my problem (using my example 2 for instance, it will return false).
Two things: is my implementation ok or is there any mistakes? Is there an easier way to implement it using STL features or anything like it?
The two most straightforward solutions are:
Copy the vectors, sort them, then use includes
Copy the elements of a group into a set or an unordered_set, and then check each element of subgroup to see if it's in the set (if C++11 were an option, you could use all_of and a lambda to implement the loop)
A variant on the same idea: make a set or an unordered_set out of the elements of subgroup, then loop through the elements of group, removing them from the set if present. Return true iff this empties out the set.
In either case, to get reasonable worst case performance guarantees you should immediately return false if subgroup is larger in size than group.
The latter, with unordered_set, has the best asymptotic complexity you can possibly expect (i.e. O(n) where n is the size of group), but I imagine the first option will be more efficient for "typical" examples.
There is a simple solution to this problem, using std:find:
bool in(std::vector<std::string> const &group,
std::vector<std::string> const &subGroup) {
std::size_t const subSize = subGroup.size();
int i = 0;
while (i < subSize && std::find(group.begin(), group.end(), subGroup[i]) != group.end()) {
i++;
}
return (i == subSize);
}
Can use a std::set
std::set<std::string> group ; // Fill it first !
std::vector<std::string> subgroups {"A","D","E"} ;
std::vector<std::string>::iterator i = subgroups.begin() ;
std::pair<std::set<std::string>::iterator,bool> p;
for( ; i != subgroups.end(); ++i )
{
p = group.insert( *i );
if( p.second ) // Present in group
{
break;
}
}
if( i == subgroups.end() )
std::cout << std::boolalpha << true ;
else
std::cout << std::boolalpha << false ;

Iterating over a vector in reverse direction

I need to iterate over a vector from the end to the beginning. The "correct" way is
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
{
//do Something
}
When //do Something involves knowing the actual index, then some calculations need to be done with rit to obtain it, like index = v.size() - 1 - (rit - v.rbegin)
If the index is needed anyway, then I strongly believe it is better to iterate using that index
for(int i = v.size() - 1; i >= 0; --i)
{
//do something with v[i] and i;
}
This gives a warning that i is signed and v.size() is unsigned.
Changing to
for(unsigned i = v.size() - 1; i >= 0; --i) is just functionally wrong, because this is essentially an endless loop :)
What is an aesthetically good way to do what I want to do which
is warning-free
doesn't involve casts
is not overly verbose
As you've noted, the problem with a condition of i >= 0 when it's unsigned is that the condition is always true. Instead of subtracting 1 when you initialize i and then again after each iteration, subtract 1 after checking the loop condition:
for (unsigned i = v.size(); i-- > 0; )
I like this style for several reasons:
Although i will wrap around to UINT_MAX at the end of the loop, it doesn't rely on that behavior — it would work the same if the types were signed. Relying on unsigned wraparound feels like a bit of a hack to me.
It calls size() exactly once.
It doesn't use >=. Whenever I see that operator in a for loop, I have to re-read it to make sure there isn't an off-by-one error.
If you change the spacing in the conditional, you can make it use the "goes to" operator.
There's nothing to stop your reverse_iterator loop also using the index as described in multiple other answers. That way you can use the iterator or index as needed in the // do the work part, for minimal extra cost.
size_t index = v.size() - 1;
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin();
rit != v.rend(); ++rit, --index)
{
// do the work
}
Though I'm curious to know what you need the index for. Accessing v[index] is the same as accessing *rit.
to be aesthetically pleasing! ;)
for(unsigned i = v.size() - 1; v.size() > i; --i)
I would prefer the reverse iterator variant, because it's still easy to interpret and allows to avoid index-related errors.
Sometimes you can simply use the BOOST_REVERSE_FOREACH, which would make your code look the following way:
reverse_foreach (int value, vector) {
do_something_with_the_value;
}
Actually speaking, you can always use foreach statements for these kinds of loops, but then they become a bit unobvious:
size_t i = 0;
foreach (int value, vector) {
do_something;
++i;
}
In C++20 one can use ranges (#include <ranges>)
//DATA
std::vector<int> vecOfInts = { 2,4,6,8 };
//REVERSE VECTOR (
for (int i : vecOfInts | std::views::reverse)
{
std::cout << i << " ";
}
or if it is required to save in a different variable.
//SAVE IN ANOTHER VARIABLE
auto reverseVecOfInts = std::views::reverse(vecOfInts);
//ITERATION
for (int i : reverseVecOfInts)
{
std::cout << i << " ";
}
Try out a do while :
std::vector<Type> v;
// Some code
if(v.size() > 0)
{
unsigned int i = v.size() - 1;
do
{
// Your stuff
}
while(i-- > 0);
}
Hi i think better way use iterator as you use in first sample and if you need get iterator index you can use
std::distance to calculate it, if i understand your question
loop condition i != std::numeric_limits<unsigned>::max() ... or use UINT_MAX if you think its to verbose.
or another way:
for(unsigned j=0, end=v.size(), i=end-1; j<end; --i, ++j)
or
for(unsigned end=v.size(), i=end-1; (end-i)<end; --i)
I think that:
for(unsigned i = v.size() - 1; i >= 0; --i)
is fine if you check
!v.empty()
earlier.
for (it = v.end()-1; it != v.begin()-1; --it)
{
}
The "goes to" operator definitely messes with my head.