Related
Basically I have a load of words in my string vector vector<string> words.
I need to make a function that searches for all the words with "ly" throughout my vector and return them, for example (golly, helpfully, mostly, nearly).
How do I use the std::find_if function to do this or is there any other way that I can do this?
I also need to find words that are longer than 7 letters in my vector, do I still use the std::find_if function with >=7 or something else?
First of all, there is a more appropriate algorithm in the standard library called std::copy_if than the std::find_if (for what you have asked).
Secondly, you need to get a different list of words asper different cases. This sounds like having a template function which wraps the std::copy_if and also provide a way to give the custom compare (e.g. a lambda function) functionalities.
Therefore I would suggest something like as follows:
#include <algorithm> // std::copy_if
#include <iterator> // std::cbegin, std::cend
template<typename Container, typename Predicate>
auto getElelmentsOf(const Container& container, const Predicate condition) /* noexcept */
{
Container result;
std::copy_if(std::cbegin(container), std::cend(container), std::back_inserter(result),
condition);
return result;
}
Now you could write something like
// all the words with "ly"
const auto words_with_ly = [](const auto& ele) {
return ele.find(std::string{ "ly" }) != std::string::npos;
};
const auto elemtsOfLy = getElelmentsOf(words, words_with_ly); // function call
// find words that are longer than 7 letters
const auto words_with_size_7_more = [](const auto& ele) { return ele.size() > 7; };
const auto elemtsOfsize7More = getElelmentsOf(words, words_with_size_7_more); // function call
(See a Live Demo Online)
You can use std::copy_if to get all elements that satisfy some conditions.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::copy_if
#include <iterator> // for std::back_inserter
using std::vector;
using std::string;
int main(void) {
vector<string>words={
"golly", "hoge", "lyric", "helpfully",
"mostly", "abcdefg", "nearly", "terrible"
};
vector<string> res_ly, res_7;
// get all words that contains "ly"
std::copy_if(words.begin(), words.end(), std::back_inserter(res_ly),
[](const string& x){ return x.find("ly") != string::npos; });
// get all words that are longer than 7 letters
std::copy_if(words.begin(), words.end(), std::back_inserter(res_7),
[](const string& x){ return x.length() > 7; });
// print what we got
std::cout << "words with \"ly\":\n";
for (const string& s : res_ly) std::cout << " " << s << '\n';
std::cout << "\nwords longer than 7 letters:\n";
for (const string& s : res_7) std::cout << " " << s << '\n';
return 0;
}
Output:
words with "ly":
golly
lyric
helpfully
mostly
nearly
words longer than 7 letters:
helpfully
terrible
If you want to use std::find_if, you can repeat searching like this:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::find_if
#include <iterator> // for std::next
using std::vector;
using std::string;
int main(void) {
vector<string>words={
"golly", "hoge", "lyric", "helpfully",
"mostly", "abcdefg", "nearly", "terrible"
};
vector<string> res_ly;
// get all words that contains "ly"
for (vector<string>::iterator start = words.begin(); ;) {
vector<string>::iterator next = std::find_if(start, words.end(),
[](const string& x){ return x.find("ly") != string::npos; });
if (next == words.end()) {
break;
} else {
res_ly.push_back(*next);
start = std::next(next, 1);
}
}
// print what we got
std::cout << "words with \"ly\":\n";
for (const string& s : res_ly) std::cout << " " << s << '\n';
return 0;
}
I could suggest the following solution.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
std::vector<std::string> copy_strings( const std::vector<std::string> &v, const std::string &s )
{
auto present = [&s]( const auto &item )
{
return item.find( s ) != std::string::npos;
};
auto n = std::count_if( std::begin( v ), std::end( v ), present );
std::vector<std::string> result;
result.reserve( n );
std::copy_if( std::begin( v ), std::end( v ),
std::back_inserter( result ),
present );
return result;
}
int main()
{
std::vector<std::string> v =
{
"golly", "helpfully", "mostly", "nearly"
};
auto result = copy_strings( v, "ly" );
for (const auto &item : result )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
golly helpfully mostly nearly
I'm trying to take a vector of strings and remove every character that's not a letter (number, symbols, etc.) I'm also not trying to use loops.
So here's an example of a vector:
std::vector<std::string> a = {"he2llo*", "3worl$d"};
And I want the string returned to look like this:
std::vector<std::string> a = {"hello", "world"};
Right now I'm trying to use the transfrom and erase algorithms, but I can't get the syntax right.
This is obviously incomplete, but it's the basic setup of what I have so far:
int trim(std::vector<std::string> a){
std::transform(a.begin(), a.end(), a.erase())
You can use std::for_each on the vector and then use the erase-remove idiom on the strings, as follows
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
int main() {
std::vector<std::string> a = {"he2llo*", "3worl$d"};
std::for_each(a.begin(), a.end(),[](auto & str){
str.erase(std::remove_if(str.begin(), str.end(), [] (auto & character){return !isalpha(character);}), str.end());
});
for(auto const & el : a)
std::cout << el << " ";
}
The output:
hello world
Recursively..
#include <iostream>
#include <vector>
std::string remove_bad_characters(std::string input, std::string result)
{
if (input.size() == 0)
{
return result;
}
if (!isalpha(input[0]))
{
return remove_bad_characters(input.substr(1), result);
}
result += input[0];
return remove_bad_characters(input.substr(1), result);
}
std::vector<std::string> edit_bad_strings(std::vector<std::string> input, std::size_t index)
{
if (index == input.size())
{
return input;
}
input[index] = remove_bad_characters(input[index], "");
return edit_bad_strings(input, index + 1);
}
int main() {
std::cout<<remove_bad_characters("h!ello!", "")<<"\n";
std::vector<std::string> good = edit_bad_strings(std::vector<std::string>{"h!ell#o", "wo0rl-d"}, 0);
for (std::string str : good)
{
std::cout<<str<<" ";
}
return 0;
}
You can use std::for_each instead of loop to traverse each element.
Then you can apply std::transform on each element of vector.
You can refer -
http://www.cplusplus.com/reference/algorithm/for_each/
http://www.cplusplus.com/reference/algorithm/transform/
Here's one way you can do it with the algorithm header and lambda functions:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main() {
std::vector<std::string> strArr = {"he2llo*", "3worl$d"};
std::transform(strArr.begin(), strArr.end(), strArr.begin(), [](std::string &str) -> std::string {
str.erase(std::remove_if(str.begin(), str.end(), [](char chr) -> bool {
return ! isalpha(chr);
}), str.end());
return str;
});
std::for_each(strArr.begin(), strArr.end(), [](const auto &str) {
std::cout << str << '\n';
});
return 0;
}
The outer lambda processes each string to erase specific characters by using remove_if, while the inner lambda just controls which characters are removed. Whether that's more readable than a loop-based solution is open to debate :-)
You can use C++20 std::erase_if
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
int main() {
std::vector<std::string> a = {"he2llo*", "3worl$d"};
std::transform(a.begin(), a.end(), a.begin(),
[](auto& str) {
std::erase_if(str, [](const auto& chr){return !isalpha(chr);});
return std::move(str);
});
for (const auto& str: a){
std::cout << str << std::endl;
}
}
You can try it in different ways with STL <algorithm>s, i implemented a functor to process each word :
#include <iostream>
#include <vector>
#include <cctype>
#include <algorithm>
class Processing{
public:
std::string operator()(std::string& value){
for_each(value.begin(), value.end(), [&](char v) mutable throw() ->
void {
auto fetch = std::find_if( value.begin(), value.end(), [&](char v)mutable throw()->
bool{
return(!isalpha(v));
});
if(*fetch){
value.erase( fetch );
}
});
return value;
}
};
int main()
{
std::vector<std::string> values = {"44h%ello333","%w%or333ld21"};
std::for_each(values.begin(),values.end(), Processing());
std::for_each(values.begin(),values.end(), [](std::string& value)->
void {
std::cout<<value<<" ";
});
return 0;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 8 years ago.
Improve this question
I was recently doing a problem on string and suddenly this thing came to my mind that, how could i arrange the words of string in increasing order of their ascii values.
for example there's a string:
ab nn ac mm
so the output should be:
ab ac mm nn
actually i want to arrange them according to sum of ascii values of each letter of a word.
like in above example
ab has a sum of (97+98)=195
ac has a sum of (97+99)=196
and so on...
I want to know is there any efficient method of doing it or is there any function in STL which i can use here?
to make the question more clear Here's a second example if a string is-
acd abz
then output is-
acd abz
as sum of ascii of each letter of "acd" is lesser than that of "abz"
acd sums to (97+99+100)=296
abz sums to (97+98+122)=317
For your custom comparison, this code should do it, using a custom comparison function object (functor), i.e. in this case an object that implements bool operator(x,y) for usage in std::sort:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
struct str_comp
{
bool operator()(const std::string &lhs, const std::string &rhs) const
{
return std::accumulate(std::begin(lhs), std::end(lhs), 0) <
std::accumulate(std::begin(rhs), std::end(rhs), 0);
}
};
int main()
{
std::string input_str {"acd abz aaayyyyy zzzaaaaa"};
std::stringstream ss {input_str};
std::vector<std::string> v_str { std::istream_iterator<std::string>{ss}, {} };
std::sort(std::begin(v_str), std::end(v_str), str_comp());
for (const auto& elem : v_str)
std::cout << elem << std::endl;
}
Or, with a lambda function like a boss:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::string input_str {"acd abz aaayyyyy zzzaaaaa"};
std::stringstream ss {input_str};
std::vector<std::string> v_str { std::istream_iterator<std::string>{ss}, {} };
std::sort(std::begin(v_str), std::end(v_str),
[](const std::string& lhs, const std::string& rhs)
{
return std::accumulate(std::begin(lhs), std::end(lhs), 0) <
std::accumulate(std::begin(rhs), std::end(rhs), 0);
}
); // end std::sort
for (const auto& elem : v_str)
std::cout << elem << std::endl;
}
You can split the string and push_back in a vector and sort the vector in the following ways:
#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
vector<string>v;
std::string s="ab nn ac mm";
istringstream t(s);
string ss;
while(t>>ss){
v.push_back(ss);
}
sort(v.begin(),v.end());
for (auto i=v.begin(); i!=v.end(); ++i){
cout<<*i<<endl;
}
return 0;
}
I assume your string has only one space, between a word and a word. Also I assume your string is trimed, which means it doesn't have any space in the head and tail of string. Let me show the code.
std::string sort_by_word_code(const std::string &src)
{
if (src.empty())
return "";
typedef std::string::const_iterator const_iterator;
typedef std::tuple<const_iterator, const_iterator, int> WordTuple;
std::vector<WordTuple> words;
const_iterator i = src.begin(), j;
int code;
while (1)
{
code = 0;
for (j = i; j != src.end() && *j != ' '; ++j)
{
code += *j;
}
words.push_back(WordTuple(i, j, code));
if (j == src.end())
break;
i = j + 1;
}
std::sort(words.begin(), words.end(),
[](const WordTuple &t1, const WordTuple &t2) { return std::get<2>(t1) < std::get<2>(t2); }
);
std::string result;
result.reserve(src.size());
for (auto it = words.begin(); ; )
{
result.insert(result.end(),
std::get<0>(*it),
std::get<1>(*it)
);
++it;
if (it == words.end())
break;
result.push_back(' ');
}
return result;
}
(live example)
The idea is simple. Create a vector which has the sum of ascii and begin/end of each word, sort it, and create a result string from it.
Well this code uses common standard functions/algorithms and is (in my opinion) efficient.
The splitting is done by a stringstream as you can see.
#include <algorithm>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main()
{
std::string input = "abz acd";
std::vector<std::string> substrings{ std::istream_iterator<std::string>{ std::stringstream{ input } }, std::istream_iterator<std::string>{} };
std::sort(std::begin(substrings), std::end(substrings),
[](const std::string& a, const std::string& b) -> bool
{
auto calcAscii = [](const std::string& str) -> int
{
int ascii = 0;
for (auto const& it : str)
{
ascii += static_cast<int>(it);
}
return ascii;
};
return calcAscii(a) < calcAscii(b);
});
std::string result;
for (auto const& it : substrings)
{
result += it + " ";
}
std::cout << result;
}
This question already has answers here:
How can I print a list of elements separated by commas?
(34 answers)
Closed 7 years ago.
Is there a way to use a std::ostream_iterator (or similar) such that the delimiter isn't placed for the last element?
#include <iterator>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main(int argc, char *argv[]) {
std::vector<int> ints = {10,20,30,40,50,60,70,80,90};
std::copy(ints.begin(),ints.end(),std::ostream_iterator<int>(std::cout, ","));
}
Will print
10,20,30,40,50,60,70,80,90,
I'm trying to avoid the trailing the delimiter. I want to print
10,20,30,40,50,60,70,80,90
Sure, you could use a loop:
for(auto it = ints.begin(); it != ints.end(); it++){
std::cout << *it;
if((it + 1) != ints.end()){
std::cout << ",";
}
}
But given C++11 range based loops this is cumbersome to track position.
int count = ints.size();
for(const auto& i : ints){
std::cout << i;
if(--count != 0){
std::cout << ",";
}
}
I'm open to using Boost. I looked into boost::algorithm::join() but needed to make a copy of the ints to strings so it was a two-liner.
std::vector<std::string> strs;
boost::copy(ints | boost::adaptors::transformed([](const int&i){return boost::lexical_cast<std::string>(i);}),std::back_inserter(strs));
std::cout << boost::algorithm::join(strs,",");
Ideally I'd just like to use a std::algorithm and not have the delimiter on the last item in the range.
Thanks!
#Cubbi pointed out in a comment that is is exactly what infix_iterator does
// infix_iterator.h
//
// Lifted from Jerry Coffin's 's prefix_ostream_iterator
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
bool first_elem;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d), first_elem(true)
{}
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (!first_elem && delimiter != 0)
*os << delimiter;
*os << item;
first_elem = false;
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
#endif
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
std::vector<int> ints = {10,20,30,40,50,60,70,80,90};
std::copy(ints.begin(),ints.end(),infix_ostream_iterator<int>(std::cout,","));
}
Prints:
10,20,30,40,50,60,70,80,90
copy could be implement as:
template<class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
while (first!=last) {
*result = *first;
++result; ++first;
}
return result;
}
The assignment to the ostream_iterator (output iterator) could be implemented as:
ostream_iterator<T,charT,traits>& operator= (const T& value) {
*out_stream << value;
if (delim!=0) *out_stream << delim;
return *this;
}
So the delimiter will be appended on every assignment to the output iterator. To avoid the delimiter being appended to the last vector element, the last element should be assigned to an output iterator without delimiter, for example:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> ints = {10,20,30,40,50,60,70,80,90};
std::copy(ints.begin(), ints.end()-1, std::ostream_iterator<int>(std::cout, ","));
std::copy(ints.end()-1, ints.end(), std::ostream_iterator<int>(std::cout));
std::cout << std::endl;
return 0;
}
Results in:
10,20,30,40,50,60,70,80,90
this would be easier. Dunno this's what you want
#include<iostream>
#include<algorithm>
#include<vector>
#include<iterator>
int main()
{
std::vector<int> ints={10,20,30,40,50,60,70,80,90};
std::copy(ints.begin(),ints.end(),std::ostream_iterator<int> (std::cout,","));
std::cout<<(char)8;
}
Use the erase method of std::string:
string join (const vector< vector<int> > data, const char* separator){
vector< vector<int> > result(data[0].size(), vector<int>(data.size()));
stringstream rowStream;
vector<string> rowVector;
for (size_t i = 0; i < data.size(); i++ ){
copy(data[i].begin(), data[i].begin() + data[i].size(), ostream_iterator<int>(rowStream, " "));
rowVector.push_back(rowStream.str().erase(rowStream.str().length()-1));
rowStream.str("");
rowStream.clear();
}
copy(rowVector.begin(), rowVector.begin() + rowVector.size(), ostream_iterator<string>(rowStream, separator));
return rowStream.str().erase(rowStream.str().length()-3);
}
how can I store the values returned from a function to a string as comma seperated values. Can anyone help me..?
const myVector &vecList = obj.get_List();
vector<myNumVector *>::const_iterator iter;
for (iter= vecList.begin(); iter!= vecList.end(); iter++)
{
string myNum = (*iter)->get_myNum();
string myNumList = ?
//myNumList should be = drt123,ret34,dfghgd234.... if these are the return values
} //can we achive this by use of some sting functions..?
As can be seen from the links I posted, there are lots of ways to do this. Here is, I believe, the simplest:
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <boost/assign/list_of.hpp>
using boost::assign::list_of;
namespace ba = boost::assign;
vector<string> victor = list_of
("Clarence Oveur")
("Roger Murdock")
("Victor Basta");
int main() {
string result;
for(vector<string>::iterator it = victor.begin();
it != victor.end();
++it) {
if(it != victor.begin()) {
result += ", ";
}
result += *it;
}
cout << result << "\n";
}
EDIT: To translate directly to OP's question:
const myVector &vecList = obj.get_List();
vector<myNumVector *>::const_iterator iter;
string myNumlist;
for (iter= vecList.begin(); iter!= vecList.end(); iter++)
{
string myNum = (*iter)->get_myNum();
if(iter!=vecList.begin()) {
nyNumList += ",";
}
myNumList += myNum;
}
EDIT: Simplified by removing bool first from previous solution.
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
int main () {
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::stringstream list;
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(list, ","));
std::cout << list.str();
return 0;
}
Outputs: 1,2,3,4,
more modern approach, also solving the trailing ","
#include <string>
#include <numeric>
#include <iostream>
int main() {
const auto v = {1, 2, 3, 4};
const auto list = std::accumulate(begin(v), end(v), std::string{}, [](const std::string& so_far, const auto& next) {
return so_far + (so_far.empty() ? "" : ", ") + std::to_string(next);
});
std::cout << list;
return 0;
}
Yes, this can be achieved using string functions, along with a handful other methods.
Given a string myNumList defined outside the loop, you could simply
myNumList += "," + myNum;
although that would add an extraneous comma in the beinning, so check if iter is pointing there first:
if(iter != vecList.begin())
myNumList += ',';
myNumList += myNum;