C++: looping over a string - iterator? - c++

Let us assume I have different functions accessing a single String str (getting a single character of it) and I want to loop through this string with every access...how could I achieve this?
For example:
string str = "abc";
function1(); // returns "a"
function2(); // returns "b"
function3(); // returns "c"
function4(); // returns "a" again
function2(); // returns "b" again
...
So basically I have different functions accessing this string str and I need some kind of iterator which gets back to the first character of str if the end of str is reached.

If you really want to use an iterator instead of indexing, you could use a cyclic_iterator, something like this:
#ifndef CYCLIC_ITERATOR_H_INC_
#define CYCLIC_ITERATOR_H_INC_
#include <iterator>
template <class FwdIt>
class cyclic_iterator_t : public std::iterator<std::input_iterator_tag, typename FwdIt::value_type> {
FwdIt begin;
FwdIt end;
FwdIt current;
public:
cyclic_iterator_t(FwdIt begin, FwdIt end) : begin(begin), end(end), current(begin) {}
cyclic_iterator_t operator++() {
if (++current == end)
current = begin;
return *this;
}
typename FwdIt::value_type operator *() const { return *current; }
};
template <class Container>
cyclic_iterator_t<typename Container::iterator> cyclic_iterator(Container &c) {
return cyclic_iterator_t<typename Container::iterator>(c.begin(), c.end());
}
#endif
This is quite minimal as iterators go--for example, it currently only supports pre-increment, not post-increment (and it's a forward iterator, so about all you can do with the iterator is increment it and dereference it).
Nonetheless, for the job you envision, it seems to be adequate.

I would just index out of the string using the % modulus operator. This will get you the wraparound behavior you want.
#include <iostream>
#include <string>
int main()
{
std::string str = "abc";
for (int i = 0; i < 10; ++i)
{
std::cout << str[i % str.size()] << " ";
}
}
Output
a b c a b c a b c a

I don't know how many times you need this to work, but here you are(You can edit it to fit with your needs):
#include <iostream>
#include <string>
int main()
{
std::string str = "abc";
bool bAgain = true;
int Max = str.length() + 1;
for(int i = 0; i < Max; i++)
{
std::cout << str[i] << "\n";
if(bAgain)
{
if(i == Max - 1)
{
i = -1;
bAgain = false;
continue;
}
}
}
}
`
Output
a
b
c
a
b
c

Related

How to create a large number of combinations lazily in C++

I want to create a combination of K elements one each from K sets. Each set can have n elements in it.
set1 = {a1, a2, a3}
set2 = {b1, b2, b3 , b4}
set3 = {c1, c2}
Required Combinations = {{a1,b1,c1}, {a1,b2,c1} ... {a3,b4,c2}}
Number of combinations = 3*4*2 =24
So if K is large and n is large we run into Out of Memory very quickly. Refer to the below code snippet how we are creating combinations today. If we create all the combinations in a case where K is relatively large, we go out of memory! So for instance, if K=20 and each set has 5 elements, the combinations are 5^20, which is extremely large in memory. So I want an alternative algorithm where I don't need to store all those combinations in memory all at a time before I start consuming the combinations.
vector<vector<string>> setsToCombine;
vector<vector<string>> allCombinations;
vector<vector<string>> *current =
new vector<vector<string>>{vector<string>()};
vector<vector<string>> *next = new vector<vector<string>>();
vector<vector<string>> *temp;
for (const auto& oneSet : setsToCombine) {
for (auto& cur : *current) {
for (auto& oneEle : oneSet) {
cur.push_back(oneEle);
next->push_back(cur);
cur.pop_back();
}
}
temp = current;
current = next;
next = temp;
next->clear();
}
for (const auto& cur : *current) {
allCombinations.push_back(cur);
}
current->clear();
next->clear();
delete current;
delete next;
You can store the indexes and lazely iterate over the combinations
#include <cstdint>
#include <iostream>
#include <vector>
using v_size_type = std::vector<int>::size_type;
using vv_size_type = std::vector<v_size_type>::size_type;
bool increment(std::vector<v_size_type> &counters, std::vector<v_size_type> &ranges) {
for (auto idx = counters.size(); idx > 0; --idx) {
++counters[idx - 1];
if (counters[idx - 1] == ranges[idx - 1]) counters[idx - 1] = 0;
else return true;
}
return false;
}
std::vector<int> get(const std::vector<std::vector<int>> &sets, const std::vector<v_size_type> &counters) {
std::vector<int> result(sets.size());
for (vv_size_type idx = 0; idx < counters.size(); ++idx) {
result[idx] = sets[idx][counters[idx]];
}
return result;
}
void print(const std::vector<int> &result) {
for (const auto el : result) {
std::cout << el << ' ';
}
}
int main() {
const std::vector<std::vector<int>> sets = {{-5, 2}, {-100, -21, 0, 15, 32}, {1, 2, 3}};
std::vector<v_size_type> ranges(sets.size());
for (vv_size_type idx = 0; idx < sets.size(); ++idx) {
ranges[idx] = sets[idx].size();
}
std::vector<v_size_type> counters(sets.size());
while (true) {
print(get(sets, counters));
std::cout << '\n';
if (!increment(counters, ranges)) break;
}
}
Godbolt
You can also use the odometer approach.
First, let us look again, what an odometer is. It looks like this:
There are several disks, with values printed on it. And if the odometer runs forward, it will show the Cartesian product of all values on the disks.
That is somehow clear, but how to use this principle? The solution is, that each set of values will be a disk, and the values of the set, will be put on the corresponding disk. With that, we will have an odometer, where the number of values on each disk is different. But this does not matter.
Also here, if a disks overflows, the next disk is incremented. Same principle like a standard odometer. Just with maybe more or less values.
And, you can put everything on a disk, not just integers. This approach will work always.
We can abstract a disk as a std::vector of your desired type. And the odometer is a std::vector of disks.
All this we can design in a class. And if we add iterator functionality to the class, we can easily handle it.
In the example below, I show only a minimum set of functions. You can add as many useful functions to this class as you like and tailor it to your needs.
The object oriented approach is often better to understand in the end.
Please check:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <initializer_list>
#include <algorithm>
#include <iterator>
using MyType = int;
using Disk = std::vector<MyType>;
using Disks = std::vector<Disk>;
// Abstraction for a very simple odometer
class Odometer {
Disks disks{};
public:
// We will do nearly everything with the iterator of the odometer class
struct iterator {
// Definitions for iterator ----------------
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = std::vector<MyType>;
using pointer = std::vector<MyType>*;
using reference = std::vector<MyType>&;
const Disks& d; // Reference to disks from super class
int overflow{}; // Indicates an overflow of all disks
std::vector<std::size_t>positions{}; // Stores position of any disks
// Iterator constructor
iterator(const Disks& dd, const int over = 0) : d(dd), overflow(over) {
positions = std::vector<std::size_t>(dd.size(), 0);
}
// Dereference iterator
value_type operator*() const {
std::vector<MyType> result(d.size());
for (std::size_t i{}; i < d.size(); ++i) result[i] = d[i][positions[i]];
return result;
};
// Comparison
bool operator != (const iterator& other) { return positions != other.positions or overflow != other.overflow; }
// And increment the iterator
iterator operator++() {
int carry = 0; std::size_t i{};
for (i=0; i < d.size(); ++i) {
if (positions[i] >= d[i].size() - 1) {
positions[i] = 0;
carry = 1;
}
else {
++positions[i];
carry = 0;
break;
}
}
overflow = (i == d.size() and carry) ? 1 : 0;
return *this;
}
};
// Begin and End functions. End is true, if there is a flip over of all disks
iterator begin() const { return iterator(disks); }
iterator end() const { return iterator(disks, 1); }
// Constructors
Odometer() {}; // Default (useless for this example)
// Construct from 2d initializer list
Odometer(const std::initializer_list<const std::initializer_list<MyType>> iil) {
for (const std::initializer_list<MyType>& il : iil) {
disks.push_back(il);
}
}
// Variadic. Parameter pack and fold expression
template <typename ... Args>
Odometer(Args&&... args) {
(disks.push_back(std::forward<Args>(args)), ...);
}
// Simple output of everything
friend std::ostream& operator << (std::ostream& os, const Odometer& o) {
for (const auto vi : o) {
for (const MyType i : vi) os << i << ' ';
os << '\n';
}
return os;
}
};
// Some test
int main() {
// Define Odometer. Initialiaze wit normal initializer list
Odometer odo1{ {1,2},{3},{4,5,6} };
// Show complete output
std::cout << odo1 << "\n\n\n";
// Create additional 3 vectors for building a new cartesian product
std::vector<MyType> v1{ 1,2 };
std::vector<MyType> v2{ 3,4 };
std::vector<MyType> v3{ 5,6 };
// Define next Odometer and initialize with variadic constructor
Odometer odo2(v1, v2, v3);
// Use range based for loop for output
for (const std::vector<MyType>& vm : odo2) {
for (const MyType i : vm) std::cout << i << ' ';
std::cout << '\n';
}
}

Avoiding or improving brute force method: Counting character repetition from all words in a dictionary text file

I wrote this utility function that will take the contents of a alpha dictionary file and will add up the repetition count of each letter or character of the alphabet.
This is what I have so far:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>
// this function just generates a map of each of the alphabet's
// character position within the alphabet.
void initCharIndexMap( std::map<unsigned, char>& index ) {
char c = 'a';
for ( unsigned i = 1; i < 27; i++ ) {
index[i] = c;
c++;
}
}
void countCharacterRepetition( std::vector<std::string>& words, const std::map<unsigned, char> index, std::map<char, unsigned>& weights ) {
unsigned count = 0;
for ( auto& s : words ) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower );
for ( std::size_t i = 0; i < s.length(); i++ ) {
using It = std::map<unsigned, char>::const_iterator;
for ( It it = index.cbegin(); it != index.cend(); ++it ) {
if ( s[i] == it->second ) {
count++;
weights[it->second] += count;
}
count = 0;
}
}
}
}
int main() {
std::vector<std::string> words;
std::string line;
std::ifstream file;
file.open( "words_alpha.txt" );
while( std::getline( file, line )
words.push_back(line);
std::map<unsigned, char> index;
initCharIndexMap(index);
std::map<char, unsigned> weights;
countCharRepetition(words, index, weights);
for (auto& w : weights)
std::cout << w.first << ' ' << w.second << '\n';
return EXIT_SUCCESS;
}
It gives me this output which appears to be valid at first glance:
a 295794
b 63940
c 152980
d 113190
e 376455
f 39238
g 82627
h 92369
i 313008
j 5456
k 26814
l 194915
m 105208
n 251435
o 251596
p 113662
q 5883
r 246141
s 250284
t 230895
u 131495
v 33075
w 22407
x 10493
y 70578
z 14757
The dictionary text file that I am using can be found from this github page.
This appears to be working. It took about 3 minutes to process on my current machine which isn't horrible, however, this seems like a brute force approach. Is there a more efficient way of doing a task like this?
If you're just counting how many times each character appears, then all you need is this:
int frequency[26] = {};
for (auto const& str : words) {
for (int i=0; i<str.size(); i++) {
frequency[tolower(str[i]) - 'a']++;
}
}
for (int i=0; i<26; i++) {
cout << char(i + 'a') << " " << frequency[i] << endl;
}
If you want to include upper and lowercase characters, change the array size to 90, remove the tolower call, and change your loop so that it prints only if i is between a and z or A and Z.
If you are just going for performance, I would say you still have to read in the file char by char - but I think all the searching is processing that could be optimised.
I would say the following pseudo code should be faster (I'll try and knock up an example later):
void read_dictionary(char *fileName)
{
// Pre-sized array (faster access)
std::array<int, 26> alphabet_count = {0};
// Open the file
FILE *file = fopen(fileName, "r");
if (file == NULL)
return; //could not open file
// Read through the file
char c;
while ((c = fgetc(file)) != EOF)
{
// If it is a letter a-z
if ( ((c >= 'a') && (c <= 'z')) ||
{
// Increment the array value for that letter
++alphabet_count[c - 'a'];
}
// else if letter A-Z
else if ( ((c >= 'A') && (c <= 'Z')) ||
{
// Increment the array value for that letter
++alphabet_count[c - 'A'];
}
}
}
The point here is that we are not searching for matches we are using the char value to index into the array to increment the alphabet letter
All of the aforementioned answers assume continuity between a and z, and history will tell you that is not always the case. A solution doesn't need to assume this, and can still be efficient.
#include <iostream>
#include <fstream>
#include <iterator>
#include <climits>
#include <cctype>
int main(int argc, char *argv[])
{
if (argc < 2)
return EXIT_FAILURE;
unsigned int count[1U << CHAR_BIT] {};
std::ifstream inp(argv[1]);
for (std::istream_iterator<char> it(inp), it_eof; it != it_eof; ++it)
++count[ std::tolower(static_cast<unsigned char>(*it)) ];
for (unsigned i=0; i<(1U << CHAR_BIT); ++i)
{
if (std::isalpha(i) && count[i])
std::cout << static_cast<char>(i) << ' ' << count[i] << '\n';
}
}
Output
[~ user]$ clang++ --std=c++14 -O2 -o main main.cpp
[~ user] time ./main /usr/share/dict/words
a 199554
b 40433
c 103440
d 68191
e 235331
f 24165
g 47094
h 64356
i 201032
j 3167
k 16158
l 130463
m 70680
n 158743
o 170692
p 78163
q 3734
r 160985
s 139542
t 152831
u 87353
v 20177
w 13864
x 6932
y 51681
z 8460
real 0m0.085s
user 0m0.073s
sys 0m0.005s
That would probably be sufficiently fast enough for your application, whatever it is.
#include <array>
#include <fstream>
#include <iostream>
int main()
{
std::ifstream file;
file.open( "words_alpha.txt" );
char c;
std::array<std::size_t, 26> counts {};
while( file >> c)
++counts[c-'a'];
for(char c = 0; c<26;++c)
std::cout<<'('<<c+'a'<<','<<counts[c]<<")\n";
}
Your version keeps track of words unnecessarily: you're simply counting characters in a file. The separation into words and lines doesn't matter. It's also unnecessary to store the words.
You could aim for readable high-level code and write something like this:
// https://github.com/KubaO/stackoverflown/tree/master/questions/letter-count-56498637
#include <cctype>
#include <fstream>
#include <iostream>
#include <iterator>
#include <limits>
#include <utility>
#include <vector>
//*
int main() {
Histogram<char, 'a', 'z'> counts;
std::ifstream file;
file.open("words_alpha.txt");
for (auto ch : make_range<char>(file)) counts.count(tolower(ch));
for (auto c : std::as_const(counts)) std::cout << c.value << ' ' << c.count << '\n';
}
This is the bare minimum of how modern C++ code should look
This requires the Histogram class, and a make_range adapter for input streams. You can't merely implement std::begin and std::end for std::ifstream, because the member end() function takes precedence and interferes (see this answer). The code below is the fragment marked //* above.
template <typename T>
void saturating_inc(T &val) {
if (val < std::numeric_limits<T>::max()) val++;
}
template <typename T, T min, T max>
class Histogram {
using counter_type = unsigned;
using storage_type = std::vector<counter_type>;
storage_type counts;
public:
template <typename U>
void count(U val) {
if (val >= min && val <= max) saturating_inc(counts[size_t(val - min)]);
}
Histogram() : counts(1 + max - min) {}
struct element {
T value;
counter_type count;
};
class const_iterator {
T val;
storage_type::const_iterator it;
public:
const_iterator(T val, storage_type::const_iterator it) : val(val), it(it) {}
const_iterator &operator++() {
++val;
++it;
return *this;
}
bool operator!=(const const_iterator &o) const { return it != o.it; }
element operator*() const { return {val, *it}; }
};
const_iterator begin() const { return {min, counts.begin()}; }
const_iterator end() const { return {0, counts.end()}; }
};
template <class C, class T>
class istream_range {
C &ref;
public:
istream_range(C &ref) : ref(ref) {}
std::istream_iterator<T> begin() { return {ref}; }
std::istream_iterator<T> end() { return {}; }
};
template <class T, class C>
istream_range<C, T> make_range(C &ref) {
return {ref};
}
This concludes the example.

Comparing function of binary_search

I am trying to run binary_search on vector of custom objects.
struct T{
string name;
T(string n):name(n){};
bool operator < ( T * n ) const {
return name < n -> name;
}
bool operator == ( T * n ) const {
return name == n -> name;
}
};
vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
bool has_3 = binary_search( t.begin(), t.end(), new T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
The comparation function should be just fine yet when i run the code has_3 equals to 0 = the element isnt present in vector. Is this problem caused by my overloading of < ? I see no reason why this shouldnt find the value. Considering the order of insertion into vector it should be sorted
Thanks for help.
There are several reasons why this shouldn't find the value:
The range must be sorted; your range is out of alphabetical order
Your comparison functionality is defined between T and T*, while you search a vector of T* for a T*.
You can fix the first problem by swapping "two" and "three", and the second problem by making a vector of T:
struct T{
string name;
T(string n):name(n){};
bool operator < ( const T &n ) const {
return name < n.name;
}
// operator == is not necessary for binary_search
};
int main() {
vector<T> t;
t.push_back(T("one"));
t.push_back(T("three"));
t.push_back(T("two"));
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
return 0;
}
Demo 1.
If you do have no way but to construct a vector of pointers, you have this ugly work-around available (I strongly recommend against it):
struct T{
string name;
T(string n):name(n){};
};
bool operator < (const T& l, const T *r) {
return l.name < r->name;
}
bool operator < (const T *l, const T &r) {
return l->name < r.name;
}
Now you can search like this:
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
Demo 2.
It's a really dumb requirement to work with a vector of pointers to dynamically allocated objects. But here is an approach that will work.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
};
// this is the comparater needed to work with pointers, but it should
// NOT be a member of T
bool pointer_comparer(const T *left, const T *right)
{
// this assumes both left and right point to valid objects
return left->name < right->name;
}
int main()
{
std::vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end(), pointer_comparer);
T *value_needed = new T("two");
bool has_3 = std::binary_search( t.begin(), t.end(), value_needed, pointer_comparer);
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// since we've been stupidly allocating objects, we need to release them
delete value_needed;
for (std::vector<T *>::iterator i = t.begin(), end = t.end();
i != end; ++i)
{
delete (*i);
}
// and since t now contains a set of dangling pointers, we need to discard them too
t.resize(0);
return 0;
}
Why do I say the requirement to work with a vector of pointers to dynamically allocated objects. Compare the above with an approach that works with a vector<T> rather than a vector<T *>.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
bool operator < (const T &) const
{
return name < n.name;
};
};
int main()
{
std::vector<T> t;
t.push_back(T("one"));
t.push_back(T("two"));
t.push_back(T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end());
bool has_3 = std::binary_search(t.begin(), t.end(), T("two"));
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// we need do nothing here. All objects use above will be properly released
return 0;
}
Note: I've written the above so it works with ALL C++ standards. Assuming C++11 and later, simplifications are possible in both cases.

Why is trying to store a pointer to function ambiguous

Here is my code:
#include <functional>
#include <iostream>
#include<vector>
using namespace std;
// vector iterator
template <class T> class vit
{
private:
//vector<T>::iterator it;
vector<T> m_v;
function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(vector<T> &v) { this->m_v = v; len = v.size(); pos = 0;};
// it= v.begin(); };
bool next(T &i) {
//if(it == m_v.end()) return false;
if(pos==len) return false;
//i = *it;
i = m_v[pos];
//if(idle) { idle = false ; return true; }
//it++;
pos++;
return true;};
//bool idle = true;
void set_same(function<bool (T,T)> fptr) { m_fptr = fptr ;};
//void set_same(function<bool(int, int)> fun) { return ; }
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
bool is_same(int a, int b) { return a == b; }
main()
{
vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
int total;
for(auto it = v.begin(); it != v.end(); it++) {
if(it == v.begin() || *it != *(it-1)) {
total = 0;
}
total += *it;
if(it+1 == v.end() || *it != *(it+1)) {
cout << total << endl;
}
}
cout << "let's gry a group" <<endl;
vit<int> g(v);
int i;
while(g.next(i)) { cout << i << endl; }
cout << "now let's get really fancy" << endl;
vit<int> a_vit(v);
//auto is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
//int total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) cout << total << endl ;
}
}
When I compile it with g++ -std=c++11 iter.cc -o iter, I get the result:
iter.cc: In function 'int main()':
iter.cc:63:17: error: reference to 'is_same' is ambiguous
a_vit.set_same(is_same);
^
iter.cc:37:6: note: candidates are: bool is_same(int, int)
bool is_same(int a, int b) { return a == b; }
^
In file included from /usr/include/c++/5.3.0/bits/move.h:57:0,
from /usr/include/c++/5.3.0/bits/stl_pair.h:59,
from /usr/include/c++/5.3.0/utility:70,
from /usr/include/c++/5.3.0/tuple:38,
from /usr/include/c++/5.3.0/functional:55,
from iter.cc:1:
/usr/include/c++/5.3.0/type_traits:958:12: note: template<class, class> struct std::is_same
struct is_same;
^
By way of explanation, I have created a class called 'vit'. It does two things: iterate over a vector, and determine if a new group has been reached.
The class function 'set_same' is supposed to store a function provided by the calling class to determine if two adjacent elements of a vector are in the same group. However, I can't seem to store the function in the class for future use by grp_begin() and grp_end() on account of the ostensible ambiguity of is_same.
What gives?
There is an is_same function defined by you and there is a struct is_same defined by the C++ Standard Library. Since you are using namespace std, your compiler doesn't know which is_same you meant to use.
It's what the error says: it's not clear whether you mean your is_same (in the global namespace) or the class template is_same (in namespace std).
You may disambiguate as follows:
::is_same
… with the leading :: meaning "in the global namespace".
Though you should consider putting your code in a namespace of its own.
Thanks guys. This is my first time touching C++ after more than a decade. I have cleaned up the code, and used a lambda to bring the "is_same" function closer to where it is called.
Did you spot the bug in my code? 'pos' was off-by-one when calling grp_begin() and grp_end(). Here is the revised code:
#include <functional>
#include <iostream>
#include <vector>
// vector iterator
template <class T> class vit
{
private:
std::vector<T> m_v;
std::function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(std::vector<T> &v) { m_v = v; len = v.size(); pos = -1;};
bool next(T &val) {
pos++;
if(pos==len) return false;
val = m_v[pos];
return true;};
void set_same(std::function<bool (T,T)> fptr) { m_fptr = fptr ;};
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos+1 == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
main()
{
std::vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
vit<int> a_vit(v);
std::function<bool (int, int)> is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
int i, total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) std::cout << total << std::endl ;
}
}
My class definition isn't bullet-proof and could be better: if the user forgets to 'set-same', for example, they'll be referring a random memory address as a function.
Nevertheless, I'm pretty chuffed with my solution so far. The class caller is relieved of all the bookkeeping relating iterating over the vector, and working out if a group boundary has been crossed.
The calling code looks very compact and intuitive to me.I can see C++ being my go to language.

(C++) Reversing a string using stacks?

I'm trying to reverse a string using stacks. It correctly reverses the string, but the for loop crashes when i reaches 0. I get a "string subscript out of range" error. Currently the for loop only decrements to 1. How can I get it to push and display s1[0]?
This is the main code:
#include <cstdlib> // Provides EXIT_SUCCESS
#include <iostream> // Provides cin, cout
#include <stack> // Provides stack
#include <string> // Provides string
using namespace std;
. . .
string reverse(string & s1)
{
stack<char> stk1;
string::size_type i;
// this for loop sets the rest of the characters
for (i = s1.size() - 1; i > 0; i--)
{
stk1.push(s1[i]);
cout << stk1.top();
}
return "The function was a success. Now that's what I call reverse psychology.";
}
This is the header file:
#ifndef MAIN_SAVITCH_STACK1_H
#define MAIN_SAVITCH_STACK1_H
#include <cstdlib> // Provides size_t
namespace main_savitch_7A
{
template <class Item>
class stack
{
public:
// TYPEDEFS AND MEMBER CONSTANT -- See Appendix E if this fails to compile.
typedef std::size_t size_type;
typedef Item value_type;
static const size_type CAPACITY = 30;
// CONSTRUCTOR
stack( ) { used = 0; }
// MODIFICATION MEMBER FUNCTIONS
void push(const Item& entry);
void pop( );
// CONSTANT MEMBER FUNCTIONS
bool empty( ) const { return (used == 0); }
size_type size( ) const { return used; }
Item top( ) const;
private:
Item data[CAPACITY]; // Partially filled array
size_type used; // How much of array is being used
};
}
#include "stack1.template" // Include the implementation.
#endif
And this is the stack implementation (a template file):
#include <cassert> // Provides assert
namespace main_savitch_7A
{
template <class Item>
const typename stack<Item>::size_type stack<Item>::CAPACITY;
template <class Item>
void stack<Item>::push(const Item& entry)
// Library facilities used: cassert
{
assert(size( ) < CAPACITY);
data[used] = entry;
++used;
}
template <class Item>
void stack<Item>::pop( )
// Library facilities used: cassert
{
assert(!empty( ));
--used;
}
template <class Item>
Item stack<Item>::top( ) const
// Library facilities used: cassert
{
assert(!empty( ));
return data[used-1];
}
}
I want to change the for loop to this, but it doesn't work:
// this for loop sets the rest of the characters
for (i = s1.size() - 1; i >= 0; i--) // i > -1 doesn't work either
{
stk1.push(s1[i]);
cout << stk1.top();
}
cout << s1[0] << "\n\n";
return "The function was a success. Now that's what I call reverse psychology.";
}
I can think of the following couple of options.
Using the string::size_type for the loop counter:
string::size_type i;
for (i = s1.size(); i > 0; i--)
{
stk1.push(s1[i-1]);
cout << stk1.top();
}
or
Using an int for the loop counter:
int i = 0;
for (i = s1.size()-1; i >= 0; i--)
{
stk1.push(s1[i]);
cout << stk1.top();
}
i is unsigned so it wraps around when it is decremented if it is equal to 0. You need to use a signed type for it or to check the boundary condition without involving negative numbers(that is, do not compare it with -1 and do not decrement it if it is 0).