I'm trying to compare two elements in a List by 'peeking' into the next element in the list. Using C++11.
Is this possible? I'm having some trouble.
#include <list>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
list<int> intList;
intList.push_back(10);
intList.push_back(20);
intList.push_back(30);
intList.push_back(30);
list<int>::iterator it;
for (it = intList.begin(); it != intList.end(); it++)
{
if (*it == *it + 1)
cout << "Duplicate: " << *it << '\n';
}
}
Yes, it's possible:
assert(!intList.empty()); // else ++begin is UB
for (list<int>::iterator it1 = intList.begin(), it2 = ++intList.begin();
it2 != intList.end(); ++it1, ++it2)
{
if (*it1 == *it2)
cout << "Duplicate: " << *it1 << '\n';
}
Your search can be simplified by using std::adjacent_find() instead (which supports std::list iterators):
Searches the range [first, last) for two consecutive identical elements.
For example:
list<int>::iterator it = std::adjacent_find(intList.begin(), intList.end());
if (it != intList.end())
cout << "Duplicate: " << *it << '\n';`
It's possible but your confronting *it with *it augmented by 1 (that is even different).
I suppose your intention was to confront two adiacent element of the list, so [thanks to DeiDei for the correction]
if ( false == intList.empty() )
{
auto it { intList.cbegin() };
auto oldVal { *it };
for ( ; ++it != intList.cend() ; oldVal = *it )
{
if ( *it == oldVal )
cout << "Duplicate: " << oldVal << '\n';
}
}
p.s.: sorry for my bad English
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 am trying to store boost integers cpp_int in an ordered set and check for next and prev elements using below code:
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/unordered_set.hpp>
#include <iostream>
namespace mp = boost::multiprecision;
using boost::unordered_set;
using namespace std;
int main() {
set<mp::cpp_int> st;
set<mp::cpp_int>::iterator it, it1, it2;
//pair<set<mp::cpp_int>::iterator,bool> res;
boost::tuples::tuple<set<mp::cpp_int>::iterator, bool> tp;
int i = 0, temp;
while(i<10){
cin>>temp;
tp = st.insert(temp);
it = get<0>(tp);
it1 = prev(it);
it2 = next(it);
cout<<*it1<<endl;
//cout<<*it2<<endl;
i++;
}
return 0;
}
However, the above code does not work as expected and crashes after couple of inputs. One such crashing sequence of inputs is:
0
1
2
3
4
0
What is the proper way of using set and iterators when using boost?
You need to check that there is a previous / next element before dereferencing the it1 and it2, e.g.:
std::set<mp::cpp_int> s;
for (size_t i = 0; i < 10; ++i){
std::cin >> temp;
auto p = s.insert(temp);
if (p.second) { // insertion succeed
auto it = p.first;
std::cout << "Inserted: " << *it << '\n';
if (it != s.begin()) { // not the first, there is a previous element
auto it1 = std::prev(it);
std::cout << "Previous: " << *it1 << '\n';
}
else {
std::cout << "Previous: None\n";
}
auto it2 = std::next(it);
if (it2 != s.end()) { // there is a next element
std::cout << "Next: " << *it2 << '\n';
}
else {
std::cout << "Next: None\n";
}
}
}
Also, if you want to find the previous and next elements of an existing element, you should use std::set::find, not std::set::insert:
auto it = s.find(temp);
if (it != s.end()) {
// Same code as above.
}
As the title says I want to print out all the elements of "group1" in this 2D map. I tried this but I just get a huge error at the for loop.
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main(){
map<string,map<int,double> > myMap;
myMap["group1"][13] = 10.41;
myMap["group1"][15] = 31.2;
//print all elements in "group1"
for (map< string, map<int,double> >::const_iterator iter =
myMap["group1"].begin(); iter != myMap["group1"].end(); ++iter)
{
cout << iter->first << '\t' << iter->second << '\n';
}
return 0;
}
Any help would be appreciated, thanks!
The type of myMap["group1"] is map<int,double> and not map<string,map<int,double>>
Then your code would look somehow like this:
const map<int,double> &grp1map = myMap["group1"];
for (map<int,double>::const_iterator iter = grp1map.begin(); iter != grp1map.end(); ++iter)
{
cout << iter->first << '\t' << iter->second << '\n';
}
You can simplify this with auto:
auto &grp1map = myMap["group1"];
for (auto iter = grp1map.begin(); iter != grp1map.end(); ++iter)
{
cout << iter->first << '\t' << iter->second << '\n';
}
But anyway you should do it like this:
for (auto &elem : myMap["group1"] )
{
cout << elem.first << '\t' << elem.second << '\n';
}
You want an iterator to your internal map<int,double>, whereas you are trying to get and iterator to your outer map<string,map<int,double> >:
int main() {
map<string, map<int, double> > myMap;
myMap["group1"][13] = 10.41;
myMap["group1"][15] = 31.2;
//print all elements in "group1"
for (map<int, double>::const_iterator iter =
myMap["group1"].begin(); iter != myMap["group1"].end(); ++iter)
{
cout << iter->first << '\t' << iter->second << '\n';
}
return 0;
}
I have a problem, I'm trying to delete an element in a string list but it doesn't work for the last position. I would also like to display the position of the iterator with an arithmetic operation.
list l = {"a","b","c", "d"};
for(std::list<string>::iterator it = l.begin(); it != l.end(); it++)
cout << " &l["<< it - l.begin() <<"]: " << &*it << " l["<< it - l.begin() <<"]: " << *it << endl;
cout << endl;
for(std::list<string>::iterator itt = l.begin(); itt != l.end(); itt++){
if(*itt == "d") itt = l.erase(itt);
cout << " &l["<< itt - l.begin() <<"]: " << &*itt << " l["<< itt - l.begin() <<"]: " << *itt << endl;
}
Thank you for your help.
It "doesn't work" because this line will cause itt to become the end() iterator when erasing the last element:
if(*itt == "d") itt = l.erase(itt);
Then the for loop does itt++ before the loop condition check, and incrementing the end() iterator is undefined behavior.
You need to modify your loop like this:
for (std::list<string>::iterator itt = l.begin(); itt != l.end(); /* */) {
if (*itt == "d") {
itt = l.erase(itt);
} else {
++itt;
}
// You cannot safely access *itt here because it might be l.end()
}
Two issues. First:
it - l.begin()
List iterators aren't random access, so they don't have operator-() defined for the obvious reason that that would be an expensive operation. If you want to do that, you have to do:
std::distance(l.begin(), it);
Second, the line:
itt = l.erase(itt);
for the last element will cause itt to become l.end(), so the subsequent itt++ is undefined behavior. What you will have to do instead is conditionally increment the iterator:
for (std::list<string>::iterator itt = l.begin(); itt != l.end(); /* nothing */) {
if (*itt == "d") {
itt = l.erase(itt);
}
else {
// cout stuff here
++itt;
}
}
Many times when creating a grammatical list (with comas), I use similar code to the following:
std::stringstream list;
int i = 0;
for (auto itemListIt = itemList.begin(); itemListIt != itemList.end(); itemListIt++)
{
list << *itemListIt;
if (i < itemList.size() - 1) list << ", ";
i++;
}
Is there some more concise way do this, perhaps without the extra variable - 'i'?
Why not test what you're really interested in; "Is there another element after this one?".
std::stringstream list;
for (auto it = roomList.begin(); it != itemList.end(); it++)
{
list << *it;
if ( it+1 != itemList.end() ) list << ", ";
}
There are two simple solutions for this. The first is to use a while
loop:
auto itemListIt = itemList.begin();
while ( itemListIt != itemList.end() ) {
list << *itemListIt;
++ itemListIt;
if ( itemListIt != itemList.end() ) {
list << ", ";
}
}
The second solution is to change the logic slightly: instead of
appending a ", " if there is more to follow, prefix one if you're not
the first element:
for ( auto itemListIt = itemList.begin(); itemListIt != itemList.end(); ++ itemListIt ) {
if ( itemListIt != itemList.begin() ) {
list << ", ";
}
list << *itemListIt;
}
You can loop over everything up to the next to last using --items.end().
Then output the last one using items.back().
#include <algorithm>
#include <iterator>
#include <sstream>
#include <vector>
#include <iostream>
int main()
{
std::ostringstream oss;
std::vector<int> items;
items.push_back(1);
items.push_back(1);
items.push_back(2);
items.push_back(3);
items.push_back(5);
items.push_back(8);
if(items.size() > 1)
{
std::copy(items.begin(), --items.end(),
std::ostream_iterator<int>(oss, ", "));
oss << "and ";
}
// else do nothing
oss << items.back();
std::cout << oss.str();
}
Output:
1, 1, 2, 3, 5, and 8
The following will work with any InputIterator input:
std::stringstream list;
auto it(std::begin(input)); //Or however you get the input
auto end(std::end(input));
bool first(true);
for (; it != end; ++it)
{
if (!first) list << ", ";
else first = false;
list << *it;
}
Or without an extra variable:
std::stringstream list;
auto it(std::begin(input)); //Or however you get the input
auto end(std::end(input));
if (it != end)
{
list << *it;
++it;
}
for (; it != end; ++it)
{
list << ", " << *it;
}
And if you want to do that with a map or other iterators that cannot do random access, as others have suggested, check for the first element:
std::stringstream query;
query << "select id from dueShipments where package in (";
for (auto it = packageList.begin(); it != packageList.end(); it++)
{
if (it != packageList.begin()) query << ", ";
query << it->second;
}
query << ")";