int i;
vector<string> names;
string s = "penny";
names.push_back(s);
i = find(names.begin(), names.end(), s);
cout << i;
I'm trying to find index of an element in vector. It's ok with iterators, but I want it as int. How can I do it?
You can use std::distance for this.
i = std::distance( names.begin(), std::find( names.begin(), names.end(), s ) );
You will probably want to check that your index isn't out of bounds, though.
if( i == names.size() )
// index out of bounds!
It's probably clearer to do this with the iterator before using std::distance, though.
std::vector<std::string>::iterator it = std::find( names.begin(), names.end(), s );
if( it == names.end() )
// not found - abort!
// otherwise...
i = std::distance( names.begin(), it );
std::vector<string>::iterator it = std::find(names.begin(), names.end(), s);
if (it != names.end()) {
std::cout << std::distance(names.begin(), it);
} else {
// ... not found
}
try
i = (find( names.begin(), names.end(), s ) - names.begin());
Edit:
Although you should consider using vector::size_type instead of an int.
Assumptions that I am making about your code:
using std::vector;
using std::cout;
using std::string;
If my assumptions are correct, then you can find the distance between the beginning of the vector and the iterator (essentially the index into the vector at which you can find such element):
using std::distance;
Like so...
vector<string>::iterator i = find(names.begin(), names.end(), s);
if (i != names.end())
{
cout << "Index " << std::distance(names.begin(), i);
}
else
{
cout << s << "not found";
}
You can just dereference your iterator
int i = *name;
Related
void rev(string& str)
{
for (auto i = str.end() -1; i != str.begin() -1; i--)
cout << *i;
cout << '\n';
}
The code above works on my system however str.begin() -1 invokes undefined behaviour as per the standard. So what is the idiomatic way of reverse traversal using iterator's but not reverse_iterator's?
This works
for (auto i = str.end(); i != str.begin(); )
{
--i;
...
}
Below is a palindrome function and a helper function that implements a reverse operation. For some reason, even though the types appear to be the same, the if comparision statement never evaluates to true. Both variables s and comp seem to be strings, and I even tried calling stoi() on both to turn them into ints but comp for some reason throws an error:
terminate called after throwing an instance of 'std::invalid_argument'
what(): stoi
Aborted (core dumped)
I'm not sure what the problem is.
bool palindrome (int n)
{
string s = to_string(n);
cout << s << endl;
string comp = rev(s);
cout << comp << endl;
if (s == comp)
{
cout << s << " " << comp << endl;
return 1;
}
return 0;
}
string rev (string &s)
{
string return_string("");
for (string::iterator it = s.end(); it != (s.begin() - 1); it--)
{
return_string += *it;
}
return return_string;
}
Your rev function has two errors. First, it computes (s.begin() - 1). Second, on its first iteration it dereferences s.end(). Both are undefined behavior.
You'll have fewer problems using reverse iterators:
string rev( const string& s )
{
string return_string;
for ( auto it = s.rbegin(); it != s.rend(); ++it )
{
return_string += *it;
}
return return_string;
}
for (string::iterator it = s.end(); it != (s.begin() - 1); it--) is certainly wrong. In the first iteration, you'll be dereferencing s.end(), and then one before s.begin() . This is undefined behavior (even s.begin() - 1 is).
Use reverse iterators:
for(auto it = s.rbegin(); it != s.rend(); ++it)
for (string::iterator it = s.end(); it != (s.begin() - 1); it--)
{
return_string += *it;
}
end() points one beyond the end of the container, so when you dereference it you are accessing memory you don't own.
Also, trying to access more memory you don't own by decrementing begin() to an address before the start of your container.
Try using a reverse iterator, reverse end and reverse begin, like so:
string rev(const string &s)
{
string return_string("");
for (string::const_reverse_iterator rit = s.rbegin(); rit != s.rend(); ++rit)
{
return_string += *rit;
}
return (return_string);
}
Is there a method in string iterator like find_first_of on string ?
Something like:
string::iterator it;
string str(" h asdasf ^& saafa");
it = FIND_FIRST_OF("&az^");
std::cout << *it << std::endl;
And the result:
a
You can do it indirectly
auto pos = str.find_first_of("&az^");
then advance the iterator
if(pos != std::string::npos) // thanks to #Mike Seymour
std::advance(it, pos);
I guess you can also do some kind of std::find with a lambda, but the above is really much more simpler and concise.
I think std::find_first_of is what you're looking for.
string::iterator it;
string str(" h asdasf ^& saafa");
string find_me ("&az^");
it = std::find_first_of (str.begin(), str.end(), find_me.begin(), find_me.end());
std::cout << *it << std::endl;
I would write a function to clean up the overhead involved in constructing/using the intermediary find_me variable if using this method with any frequency.
Try this:
std::string::size_type position = example.find_first_of(".");
if (position != std::string::npos)
{
std::advance(string_iterator, position);
}
else
{
string_iterator = example.end();
}
Class std::string has its own methods find_first_of and find_last_of apart from other find methods.
Here is a demonstrative program
#include <iostream>
#include <string>
int main()
{
std::string s( " h asdasf ^& saafa" );
auto pos = s.find_first_of( "&az^" );
if ( pos != std::string::npos ) std::cout << s[pos] << std::endl;
pos = s.find_last_of( "&az^" );
if ( pos != std::string::npos ) std::cout << s[pos] << std::endl;
return 0;
}
The program output is
a
a
Here is another demonstrative program that finds all characters in the string that are specified in the character literal
#include <iostream>
#include <string>
int main()
{
std::string s( " h asdasf ^& saafa" );
for ( std::string::size_type pos = 0;
( pos = s.find_first_of( "&az^", pos ) ) != std::string::npos;
++pos )
{
std::cout << pos << ": " << s[pos] << std::endl;
}
return 0;
}
The program output is
4: a
7: a
11: ^
12: &
15: a
16: a
18: a
Knowing the found position you always can get the corresponding iterator in the object:
std::string::iterator it = std::next( s.begin(), pos );
or
auto it = std::next( s.begin(), pos );
or simply
std::string::iterator it = s.begin() + pos;
Also there is standard algorithm std::find_first_of declared in header <algorithm> that also can be used with objects of type std::string.
I have created a vector<string> names; which stores peoples first names. I want to take each name and create two variables first_letter and last_letter which contains the first and last characters of each name. However I am not quite sure how to get this done since I am just starting with c++. Can anyone explain to me how this can be done, and possibly provide an example?
In C++11 it got easier:
for (std::string& name : names) {
char first_letter = name.front();
char last_letter = name.back();
// do stuff
}
Before that, you'd have to access them directly using operator[]:
for (size_t i = 0; i < names.size(); ++i) {
std::string& name = names[i];
char first_letter = name[0];
char last_letter = name[name.size() - 1];
// do stuff
}
Assuming name is your string and you're OK with using C++11, name.front() and name.back() will work, otherwise dereference the iterator: *name.begin() and *name.rbegin(). Though you'd check whether the name is empty or not:
if (!name.empty()) {
// Safe to proceed now
}
You can iterate over names like (range loop - since C++11)
for (auto& name : names) {
// Do things with individual name
}
or (for older C++)
for (vector<string>::iterator it = names.begin(); it != names.end(); it++) {
// Do things with individual name (*it)
}
It's advised to use constant iterators where possible, if you're not planning to modify strings, replace auto with const auto and ::iterator with ::const_iterator.
Use the string functions front() and back().
Make sure that the string is not empty before using these functions:
Assuming that i is an index into your vector:
if ( !names[i].empty() )
{
char fChar = names[i].front();
char bChar = names[i].back();
}
Create a function to get the two letters from a single string:
std::pair<char, char>
first_and_last(const std::string& s)
{
if (s.length() == 0)
throw std::runtime_error("Empty string!")
return {s.front(), s.back()};
}
(for C++03 return std::make_pair(s[0], s[s.length()-1]) or another of the ways to do it shown by the other answers.)
Then apply that function to each name in turn, saving the results in a new vector:
std::vector<std::pair<char, char>> letters;
letters.reserve(names.size());
std::transform(names.begin(), names.end(), std::back_inserter(letters), first_and_last);
Or use the C++11 range-based for loop:
std::vector<std::pair<char, char>> letters;
letters.reserve(names.size());
for (const auto& name : names)
letters.push_back( first_and_last(name) );
Something like this? There's no error checking, but it's a start.
vector<string> names = ...;
for (vector<string>::iterator i = names.begin(); i != names.end(); ++i)
{
string first_letter = i->substr(0, 1);
string last_letter = i->substr(i->size() - 1, 1);
}
First off, of course, you start with a loop to iterate through the vector.
Then you get those characters with substr, it would look something like this
vector <string>::iterator it;
for(it = names.begin(); it != names.end(); it++)
{
string first = (*it).substr(0, 1);
string second = (*it).substr((*it).length()-1, 1);
..
do whatever you want to
..
}
Consider the following approach
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <utility>
#include <iterator>
int main()
{
std::vector<std::string> v { "Hello", "NinjaZ", "How", "do", "you", "do" };
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << std::endl;
std::vector<std::pair<char, char>> v2;
v2.reserve( v.size() );
std::transform( v.begin(), v.end(),
std::back_inserter( v2 ),
[]( const std::string &s )
{
return std::make_pair( s.front(), s.back() );
} );
for ( const auto &p : v2 )
{
std::cout << p.first << ' ' << p.second << std::endl;
}
return 0;
}
The output is
Hello NinjaZ How do you do
H o
N Z
H w
d o
y u
d o
Instead of the algorithm std::transform you could use an ordinary range based for loop. For example
for ( const auto &s : v ) v2.push_back( { s.front(), s.back() } );
There are many ways to skin this cat.
Here's another short readable example using C++11. What this brings to the table is the use of std::vector::emplace_back which allows for in-place construction of elements, as opposed to move- or copyconstructing. Also shorter syntax which is nice.
Say you have a container that stores the pairs of letters.
std::vector<std::pair<char, char>> letters;
Then use this:
for (auto&& name : names)
letters.emplace_back(name.front(), name.back());
If you want to throw on empty name strings, simply add a statement before the std::vector::emplace_back statement:
if (name.empty()) throw std::runtime_error("Empty string!");
I have to implement a vector using an array in C++ that is used to count the number of unique words from the input. It reads the input and then adds to the words to a struct which contains its count and the unique word and then this is added to the vector. I have successfully implemented insert. The problem is that I can't get the inserting/ incrementing unique word count to work (elements aren't added to the vector). Here is my code:
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "MyVector.h"
using namespace std;
struct wordCount{
string val;
int count;
};
int main(int argc, char** argv) {
enum { total, unique,individual } mode = total;
for (int c; (c = getopt(argc, argv, "tui")) != EOF;) {
switch(c) {
case 't': mode = total; break;
case 'u': mode = unique; break;
case 'i': mode = individual; break;
}
}
argc += optind;
argv += optind;
string word;
Vector<wordCount> words;
Vector<wordCount>::iterator it;
int count = 0;
while (cin >> word) {
count++;
if(mode == unique || mode == individual){
for(it=words.begin();it != words.end();it++){
if((it-1)->val <= word && it->val >= word){
// Found word, increment its count
if(it->val == word){
it->count++;
break;
}
// Otherwise insert the new unique word
else{
cout << "adding unique word" << endl;
wordCount* wc;
wc = new wordCount;
wc->val = word;
wc->count = 1;
words.insert(it,*wc);
break;
}
}
}
}
}
switch (mode) {
case total: cout << "Total: " << count << endl; break;
case unique: cout << "Unique: " << words.size() << endl; break;
case individual:
for(it=words.begin();it!=words.end();it++){
cout << it->val << ": " << it->count << endl;}
break;
}
}
It's hard to say anything without seeing your implementation of
Vector. If we assume it adheres to the standard container
conventions (and doesn't have an error in trying to do so): you
iterate starting with it.begin(), but immediately access
it-1. That's undefined behavior for a standard container. (I
don't know what it will do with your implementation ofVector`,
but it would take some tricky code to make it work.)
At a higher level, there seems a basic inconsistency: you're
keeping the vector sorted, but still using linear search. If
you're using linear search, there's no point in keeping the
vector sorted; just use:
Vector<wordCount>::iterator it = words.begin();
while ( it != words.end() && *it != word ) {
++ it;
}
if ( it == words.end() ) {
// not found, append to end...
} else {
// found, do whatever is appropriate...
}
(although I'd probably append to end, recover the iterator to
the newly inserted element, and treat it as if it were found).
Alternatively, if you're keeping the vector sorted, use a binary
search, not a linear search.
In either case, put the search in a separate function. (If this
wasn't homework, I'd say just use std::vector and either
std::find_if or std::lower_bound.)
Also, why the new in the innermost else? A more reasonable
approach would be to provide a constructor for wordCount
(which sets the count to 0), and do something like:
if ( ! found ) {
it = words.insert( wordCount( word ) );
}
++ it->count;
The definition of found will depend on whether you're using
binary search or not. In terms of the standard, this would be
either:
Vector<wordCount>::iterator it
= std::find_if( words.begin(), words.end(), MatchWord( word );
if ( it == words.end() ) {
it = words.insert( words.end(), wordCount( word ) );
}
++ it-count;
or
Vector<wordCount>::iterator it
= std::lower_bound( words.begin(), words.end(), word, CompareWord() );
if ( it == words.end() || it->val != word ) {
it = words.insert( wordCount( word ) );
++ it->count;
You should probably strive for something similar, with
a separate lookup function, returning either end, or the
position for the insertion when the value isn't found.
This keeps the various concerns clearly separated, and avoids
the excessive nesting in your code. (You should probably try to
avoid break in general, and in multiply nested ifs, it is
completely inacceptable—you'll notice that one of the
other people answering missed them, and misunderstood the
control flow because of it.)
Well, why don't you use a map? That's exactly what it's for, mapping from one thing to another. From a string (the word) to an int (the number of occurences) in your case. Or do you have to use a vector?
Try to use a std::map.
Counter::Map words;
Counter count(words);
std::for_each(
std::istream_iterator<std::string>(myInStream /*std::cin*/),
std::istream_iterator<std::string>(),
count);
std::copy(
words.begin(),
words.end(),
std::ostream_iterator<Counter::Map::value_type>(myOutStream /*std::cout*/, "\n"));
The Counter functor could look like this
struct Counter
{
typedef std::map<std::string, size_t> Map;
Counter(Map& m) : words(&m) {}
void operator()(const std::string& word)
{
Map::iterator it = words->lower_bound(word);
if (it == words->end() || it->first != word)
words->insert(it, std::make_pair(word, 1));
else
++it->second;
}
Map* words;
};
Using a std::vector
struct CounterVector
{
typedef std::vector<std::pair<std::string, size_t> > Vector;
CounterVector(Vector& m) : words(&m) {}
struct WordEqual
{
const std::string* s;
WordEqual(const std::string& w) : s(&w) {}
bool operator()(Vector::const_reference p) const {
return *s == p.first;}
};
void operator()(const std::string& word)
{
Vector::iterator it = std::find_if(
words->begin(), words->end(), WordEqual(word));
if (it == words->end())
words->push_back(std::make_pair(word,1));
else
++it->second;
}
Vector* words;
};