Condition based for loop selection.
if(valid)
for (std::multimap<int,int>::reverse_iterator rit=id_count.rbegin(); mcount<10 && rit!=id_count.rend();++rit)
else
for (std::multimap<int,int>::iterator rit=id_match.begin(); mcount<10 && rit!=id_match.end();++rit)
{
//this is common for both for loop
}
how to achieve this in C++?
You have no choice but putting the common part in a function, very roughly like this:
void somefunction(...)
{
//this is common for both for loops
}
if (valid)
{
for (std::multimap<int,int>::reverse_iterator rit=id_count.rbegin(); mcount<10 && rit!=id_count.rend();++rit)
somefunctiuon(...);
}
else
{
for (std::multimap<int,int>::iterator rit=id_match.begin(); mcount<10 && rit!=id_match.end();++rit)
somefunctiuon(...);
}
This is arguably most useful as an illustration that it's not worth combining the loop logic, though it does work. Provided here for interest value...
#include <iostream>
#include <map>
int main()
{
std::multimap<int,int> id_count = { {1,2}, {9, -2}, {1,44}, {2,3}, {3,5}, {7,34} };
for (int valid = 0; valid < 2; ++valid)
{
std::cout << "valid " << valid << '\n';
int mcount = 0;
for (std::multimap<int,int>::iterator it = valid ? id_count.rbegin().base()
: id_count.begin();
mcount<10 && (valid ? it--!=id_count.begin() : it!=id_count.end());
(valid ? it : ++it), ++mcount)
{
std::cout << "[mcount " << mcount << "] "
<< it->first << ',' << it->second << '\n';
}
std::cout << '\n';
}
}
You can create a template function:
#include <map>
#include <iostream>
template<typename I> void func(I begin, I end) {
int mcount = 0;
for (I it = begin; mcount < 10 && it != end; ++it) {
++mcount;
std::cout << "[mcount " << mcount << "] "
<< it->first << ',' << it->second << '\n';
}
}
int main() {
std::multimap<int,int> id_count = { {1,2}, {9, -2}, {1,44}, {2,3}, {3,5}, {7,34} };
for (int valid = 0; valid < 2; ++valid) {
std::cout << "valid " << valid << '\n';
if (valid) {
func(id_count.rbegin(), id_count.rend());
} else {
func(id_count.begin(), id_count.end());
}
std::cout << '\n';
}
}
But IMHO this solution is a bit complicated, so consider other ways (like placing the loop body in a function).
You can try "#if valid", like:
#if 0
for(i=1;i<10;++i)
#else
for(i=2;i<9;++i)
#endif
{
cout << i << endl;
}
In C++14 you also have an option to use generic lambdas:
auto common_code = [/* Capture state if needed */] ( auto& Iter )
{
// Your common code
};
if ( valid )
for ( std::multimap<int, int>::reverse_iterator rit = id_count.rbegin(); mcount < 10 && rit != id_count.rend(); ++rit )
common_code( rit );
else
for ( std::multimap<int, int>::iterator rit = id_match.begin(); mcount < 10 && rit != id_match.end(); ++rit )
common_code( rit );
Related
I create and modify a simple list. I replace the element at index 1 of the list. How would I semantically accomplish the same thing with a while loop. The tutorial instructor remarked that the current code is quite ugly and a while loop would accomplish the same thing in a much more simple and pretty fashion. I can't figure it out.
#include <iostream>
#include <list>
int main() {
std::list<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
numbers.push_front(0);
std::list<int>::iterator it = numbers.begin();
it++;
numbers.insert(it, 100);
std::cout << "Current element is: " << *it << '\n';
std::list<int>::iterator eraseIt = numbers.begin();
eraseIt++;
eraseIt = numbers.erase(eraseIt);
std::cout << "erasing at element: " << *eraseIt << '\n';
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end();) {
if (*it == 2) {
numbers.insert(it, 1234);
}
if (*it == 1) {
it = numbers.erase(it);
} else {
it++;
}
}
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end();
it++) {
std::cout << *it << '\n';
}
return 0;
}
You can probably do this if iterators are required:
// ...
std::list<int>::iterator it = ++numbers.begin();
numbers.insert(it, 100);
std::cout << "Current element is: " << *it << '\n';
std::list<int>::iterator eraseIt = ++numbers.begin();
eraseIt = numbers.erase(eraseIt);
std::cout << "erasing at element: " << *eraseIt << '\n';
it = numbers.begin();
while (it != numbers.end())
{
if (*it == 2) {
numbers.insert(it, 1234);
}
if (*it == 1) {
it = numbers.erase(it);
}
else {
++it;
}
}
for (auto& i : numbers)
{
std::cout << i << std::endl;
}
// ...
I was to solve one question on hackerrank related to lower bound in C++. My code was able to pass all the test cases which had no time limit but failed in all time bound test cases. You can find the hackerrank question from this link:
https://www.hackerrank.com/challenges/cpp-lower-bound/problem?utm_campaign=social-buttons&utm_medium=linkedin&utm_source=challenge
Below is my code. Please tell me how I can optimize it.
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> v;
int elementCount = 0, queryCount = 0, tempElement = 0;
std::cin >> elementCount;
for(int i=0; i<elementCount; ++i)
{
std::cin >> tempElement;
v.push_back(tempElement);
}
std::vector<int>::iterator elementPosition;
const std::vector<int>::iterator midElement = v.begin() + v.size()/2;
std::cin >> queryCount;
for(int q=0; q<queryCount; ++q)
{
std::cin >> tempElement;
if(tempElement <= *midElement)
{
elementPosition = find(v.begin(), midElement+1, tempElement);
if(elementPosition == (midElement+1))
{
elementPosition = lower_bound(v.begin(), midElement, tempElement);
std::cout << "No " << (elementPosition-v.begin())+1 << std::endl;
}
else
{
std::cout << "Yes " << (elementPosition-v.begin())+1 << std::endl;
}
}
else
{
elementPosition = find(midElement+1, v.end(), tempElement);
if(elementPosition != v.end())
{
std::cout << "Yes " << (elementPosition-v.begin())+1 << std::endl;
}
else
{
elementPosition = lower_bound(midElement+1, v.end(), tempElement);
std::cout << "No " << (elementPosition-v.begin())+1 << std::endl;
}
}
}
return 0;
}
You have over complicated the solution with unnecessary find() + lower_bound.
Just use lower_bound() to find the element
If found, print yes
If not, print no
auto elementPosition = lower_bound(v.begin(), v.end(), tempElement);
size_t pos = std::distance(v.begin(), elementPosition);
if (v[pos] == tempElement) {
//print yes
} else {
// print no
}
I have a map of vectors in C++. For each vector, I'd like to delete entries that meet a certain condition. If a vector ends up empty, I'd like to delete it from the map. I know deletion can mess up iterators, and doubly iterating makes this even more confusing for me. What's the best way to accomplish this?
The standard mutating container loop:
for (auto it = m.begin(); it != m.end(); )
{
// work
if (/* need to delete */) // e.g "if (it->second.empty())"
{
it = m.erase(it);
}
else
{
++it;
}
}
Here is a demonstrative program that shows how it can be done
#include <iostream>
#include <map>
#include <vector>
int main()
{
std::map<int, std::vector<int>> m =
{
{ 1, { 1, 2 } },
{ 2, { 2 } },
{ 3, { 3, 4 } },
{ 4, { 4 } }
};
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
for ( auto it = m.begin(); it != m.end(); )
{
it->second.erase( it->second.begin() );
if ( it->second.empty() ) it = m.erase( it );
else ++it;
}
std::cout << std::endl;
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The program output is
1: 1 2
2: 2
3: 3 4
4: 4
1: 2
3: 4
I am trying to subtract the 1st element of the std::map from every other element of that same std::map. I couldn't find anything about that. Is it possible? for example :
std::map<char,int> bar;
bar['a']=11; //should be deleted from other elements
bar['b']=22;
bar['c']=33;
bar['d']=44;
std::cout << "bar contains:\n";
for (std::map<char,int>::iterator it=bar.begin(); it!=bar.end(); ++it)
{
std::cout <<"key: " <<it->first << " Value=> " << it->second << '\n'; //can i delete here??
//i want to delete value of a from value of b and update the value of b
}
//the new map should be look like as follows
//bar['a']=11; //or may be 0
//bar['b']=11;
//bar['c']=22;
//bar['d']=33;
Any ideas to do it easily with map in c++?
Thanks.
C++11 Solution
You could use std::for_each for this
std::for_each(std::next(bar.begin()), bar.end(), [&bar](std::pair<const char, int>& x){ x.second -= bar.begin()->second; });
For example
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
int main()
{
std::map<char,int> bar;
bar['a']=11;
bar['b']=22;
bar['c']=33;
bar['d']=44;
std::for_each(std::next(bar.begin()), bar.end(), [&bar](std::pair<const char, int>& x){ x.second -= bar.begin()->second; });
std::cout << "bar contains:\n";
for (std::map<char,int>::iterator it=bar.begin(); it!=bar.end(); ++it)
{
std::cout << "key: " << it->first << " Value=> " << it->second << '\n';
}
}
Output (working demo)
bar contains:
key: a Value=> 11
key: b Value=> 11
key: c Value=> 22
key: d Value=> 33
And if you want to subtract even the first element from itself, just remove the std::next call and capture the value you want to subtract out, since you're going to modify the first map entry.
auto const sub = bar.begin()->second;
std::for_each(bar.begin(), bar.end(), [&sub](std::pair<const char, int>& x){ x.second -= sub; });
C++03 Solution
To subtract the first element from everything except the first element itself
int value = bar.begin()->second;
std::map<char, int>::iterator it = bar.begin();
std::advance(it, 1);
for (; it != bar.end(); ++it)
{
it->second -= value;
}
To include the first element
int value = bar.begin()->second;
for (std::map<char, int>::iterator it = bar.begin(); it != bar.end(); ++it)
{
it->second -= value;
}
You simply need to loop over the map and subtract the value associated with the "first" key from each element, storing the result back into the same element. One approach to that is shown below:
Live example at http://coliru.stacked-crooked.com/a/1bc650592027f5f3
#include <iostream>
#include <map>
int main() {
// Set up the problem...
std::map<char, int> foo;
foo['a'] = 11;
foo['b'] = 22;
foo['c'] = 33;
foo['d'] = 44;
// Obtain the value of the 'a' key...
const int value = foo['a'];
// Subtract that value from each element...
for (auto& element : foo) {
element.second -= value;
}
// Output the map to verify the result...
for (auto& element : foo) {
std::cout << element.first << ": " << element.second << "\n";
}
return 0;
}
Note that if you loop over the entire map, you need to store the initial value of foo[a], since you'll zero it during the iterative subtraction. You can avoid this by using iterators and skipping over the first element using e.g. std::next(foo.begin()). Other answers demonstrate this technique, so I won't duplicate it here.
You can use standard algorithm std::for_each declared in header <algorithm>
If your compiler supports C++ 2014 then the code can look like
#include <iostream>
#include <map>
#include <algorithm>
#include <iterator>
int main()
{
std::map<char, int> bar;
bar['a'] = 11;
bar['b'] = 22;
bar['c'] = 33;
bar['d'] = 44;
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
if ( !bar.empty() )
{
std::for_each( std::next( bar.begin() ), bar.end(),
[value = ( *bar.begin() ).second] ( auto &p ) { p.second -= value; } );
}
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
}
The program output is
{ a, 11 } { b, 22 } { c, 33 } { d, 44 }
{ a, 11 } { b, 11 } { c, 22 } { d, 33 }
If your compiler supports only C++ 2011 then the main loop in the program can look like
if ( !bar.empty() )
{
auto value = ( *bar.begin() ).second;
std::for_each( std::next( bar.begin() ), bar.end(),
[value] ( std::pair<const char, int> &p ) { p.second -= value; } );
}
The same can be done using for example the range based for loop
#include <iostream>
#include <map>
int main()
{
std::map<char, int> bar;
bar['a'] = 11;
bar['b'] = 22;
bar['c'] = 33;
bar['d'] = 44;
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
if ( !bar.empty() )
{
auto value = ( *bar.begin() ).second;
bool first = true;
for ( auto &p : bar )
{
if ( first ) first = !first;
else p.second -= value;
}
}
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
}
Also if the element by which all other elements should be decreased is not necessary the first element of the map then you can use the following approach
#include <iostream>
#include <map>
#include <algorithm>
#include <iterator>
int main()
{
std::map<char, int> bar;
bar['a'] = 11;
bar['b'] = 22;
bar['c'] = 33;
bar['d'] = 44;
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
if ( !bar.empty() )
{
// the initializer can be any element not only the first one
const auto &value = *bar.begin();
for ( auto &p : bar )
{
if ( p.first != value.first ) p.second -= value.second;
}
}
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
}
int value = bar.begin()->second;
for(std::map<char,int>::reverse_iterator it=bar.rbegin(); it != bar.rend(); it++) {
it->second -= bar.begin()->second;
}
bar.begin()->second = value;
I have to print out the size of the vector and all the contents inside it. But my for loop doesnt iterate, it doesn't go up by one but instead stays at the value 0 for the whole loop.
#include "stdafx.h"
#include <string.h>
#include <string>
#include <iostream>
#include <cctype>
#include <vector>
#include <list>
using std::string;
using std::vector;
vector<int> v2(10);
for( auto i : v2)
{
if( i == 0 )
{
std::cout << v2.size() << std::endl;
}
std::cout << "Element value " << (i) << " is " << v2[i] << std::endl;
}
So I only want to print the size once, at the start. Then print out each element value which I know will be 0 by default. But it just prints out "Element value 0 is 0" 9 times.
If you want at first to print out the size of the vector then place this output statement before the range based for statement
std::vector<int> v2(10);
std::cout << v2.size() << std::endl;
size_t i = 0;
for ( auto x : v2 )
{
std::cout << "Element value " << i++ << " is " << x << std::endl;
}
But if you are using a count then it would be better to use the ordinary for statement
std::vector<int> v2(10);
std::cout << v2.size() << std::endl;
for ( std::vector<int>::size_type i = 0; i < v2.size(); i++ )
{
std::cout << "Element value " << i << " is " << v2[i] << std::endl;
}
Your question indicates that you want to treat the first element differently. This does not work with range-based for loops out of the box. You have two options:
Use an extra variable to remember whether the first iteration was made.
Use a traditional loop, using an index variable or an iterator.
Example for 1:
bool first_iteration = true;
for( auto i : v2)
{
if (first_iteration)
{
std::cout << v2.size() << std::endl;
first_iteration = false;
}
// ...
}
Example for 2:
for (auto iter = v2.begin(); iter != v2.end(); ++iter)
{
if (iter == v2.begin())
{
std::cout << v2.size() << std::endl;
}
// ...
}