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);
}
Related
how can i delete the rest of the characters?
s.erase(std::unique(s.begin(), s.end()), s.end());
This only deletes the duplicated characters and doesn't remove the first presence of the character.
Example: "Hello World"
would return "he wrd"
There's no builtin for this function, but you can write your own generic algorithm to accomplish this:
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
template <class C>
auto erase_if_duplicate(C& c)
{
using T = typename C::value_type;
const auto begin = c.begin();
const auto end = c.end();
std::unordered_map<T, std::size_t> count{};
std::for_each(
begin, end,
[&] (const T& v) { ++count[v]; });
const auto it = std::remove_if(
begin, end,
[&] (const T& v) { return count.at(v) > 1; });
return c.erase(it, end);
}
int main()
{
// example usage
std::string s{"hello world"};
erase_if_duplicate(s);
std::cout << s; // he wrd
}
Try it on godbolt.org
From what I understand, you want to remove all occurrences of a character from a string if it has duplicates (its count is bigger than 2), and the removal is not case-sensitive (meaning H will be treated as h).
So, you can create a frequency map of all character, and if its count is >1 then remove all of its occurrences with erase():
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
string x; getline(cin, x);
map<char, int> freq;
for (size_t i = 0; i < x.size(); i++)
{
x[i] = tolower(x[i]); //lowercase all the character
freq[x[i]]++; //frequency of character
}
x.erase(remove_if(x.begin(), x.end(),
[&] (const char& c) { return freq[c] > 1; }),
x.end());
cout << x;
}
Output :
Hello world
he wrd
Another example:
ABbcDdDEfF
ace
I need to print out a dozen text files with words and there frequency(how many times the 'word' shows up) but its not meant to print out words that only appear once. How can I not print those words out. I want to know how to basically be able to do things with the value of the 2nd value of my vector.
#include <iostream>
#include <map>
#include <fstream>
#include <string>
#include<bits/stdc++.h>
#include <iterator>
using namespace std;
template <class KTy, class Ty>
void PrintMap(map<KTy, Ty> map)
{
typedef typename std::map<KTy, Ty>::iterator iterator;
std::vector<std::pair<std::string,int>> vector( map.begin(), map.end() );
std::sort( vector.begin(), vector.end(),
[]( const auto & lhs, const auto rhs )
{ return lhs.second > rhs.second;} );
for ( const auto & item : vector )
if (item.second == 1)
::cout << item.first << ": " << item.second << std::endl;
}
int main(void)
{
vector <string> File;
File.push_back("data.txt");
File.push_back("data_1.txt");
File.push_back("data_2.txt");
File.push_back("data_3.txt");
File.push_back("data_4.txt");
File.push_back("data_5.txt");
File.push_back("data_6.txt");
File.push_back("data_7.txt");
File.push_back("data_8.txt");
File.push_back("data_9.txt");
map<string, unsigned int> wordsCount;
for (int i=0; i < File.size(); i++)
{
ifstream fileStream(File[i]);
if (fileStream.is_open())
while (fileStream.good())
{
string word;
fileStream >> word;
if (wordsCount.find(word) == wordsCount.end())
wordsCount[word] = 1;
else
wordsCount[word]++;
}
else
{
cerr << "ERROR." << endl;
return EXIT_FAILURE;
}
}
PrintMap(wordsCount);
return EXIT_SUCCESS;
}
If you don't want to print words that occur only once, change:
if (item.second == 1)
to:
if (item.second != 1)
Hey so I'm having trouble figuring out the code to count the number of unique words. My thought process in terms of psudeocode was first making a vector so something like vector<string> unique_word_list;Then I would get the program to read each line so I would have something likewhile(getline(fin,line)). The hard part for me is coming up with the code where I check the vector(array) to see if the string is already in there. If it's in there I just increase the word count(simple enough) but if its not in there then I just add a new element to the vector. I would really appreciate if someone could help me out here. I feel like this is not hard but for some reason I can't think of the code for comparing the string with whats inside of the array and determining if its a unique word or not.
Don't use a vector - use a container that maintains uniqueness, like std::set or std::unordered_set. Just convert the string into lower case (using std::tolower) before you add it:
std::set<std::string> words;
std::string next;
while (file >> next) {
std::transform(next.begin(), next.end(), next.begin(), std::tolower);
words.insert(next);
}
std::cout << "We have " << words.size() << " unique words.\n"
Cannot help myself writing an answer that makes use of C++ beautiful library. I'd do it like this, with a std::set:
#include <algorithm>
#include <cctype>
#include <string>
#include <set>
#include <fstream>
#include <iterator>
#include <iostream>
int main()
{
std::ifstream ifile("test.txt");
std::istream_iterator<std::string> it{ifile};
std::set<std::string> uniques;
std::transform(it, {}, std::inserter(uniques, uniques.begin()),
[](std::string str) // make it lower case, so case doesn't matter anymore
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
});
// display the unique elements
for(auto&& elem: uniques)
std::cout << elem << " ";
// display the size:
std::cout << std::endl << uniques.size();
}
You can also define a new string type in which you change the char_traits so the comparison becomes case-insensitive. This is the code you'd need (much more lengthy than before, but you may end up reusing it), the char_traits overload is copy/pasted from cppreference.com:
#include <algorithm>
#include <cctype>
#include <string>
#include <set>
#include <fstream>
#include <iterator>
#include <iostream>
struct ci_char_traits : public std::char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while ( n-- != 0 ) {
if ( toupper(*s1) < toupper(*s2) ) return -1;
if ( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
while ( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};
using ci_string = std::basic_string<char, ci_char_traits>;
// need to overwrite the insertion and extraction operators,
// otherwise cannot use them with our new type
std::ostream& operator<<(std::ostream& os, const ci_string& str) {
return os.write(str.data(), str.size());
}
std::istream& operator>>(std::istream& os, ci_string& str) {
std::string tmp;
os >> tmp;
str.assign(tmp.data(), tmp.size());
return os;
}
int main()
{
std::ifstream ifile("test.txt");
std::istream_iterator<ci_string> it{ifile};
std::set<ci_string> uniques(it, {}); // that's it
// display the unique elements
for (auto && elem : uniques)
std::cout << elem << " ";
// display the size:
std::cout << std::endl << uniques.size();
}
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;
}
I would like to know if there is an elegant way or a built-in function to convert vector<double> to vector<string>. What I've done is simple
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
std::vector<std::string> doubeVecToStr(const std::vector<double>& vec)
{
std::vector<std::string> tempStr;
for (unsigned int i(0); i < vec.size(); ++i){
std::ostringstream doubleStr;
doubleStr << vec[i];
tempStr.push_back(doubleStr.str());
}
return tempStr;
}
int main( int argc, char* argv[] )
{
std::vector<double> doubleVec;
doubleVec.push_back(1.0);
doubleVec.push_back(2.1);
doubleVec.push_back(3.2);
std::vector<std::string> doubleStr;
doubleStr = doubeVecToStr(doubleVec);
for (unsigned int i(0); i < doubleStr.size(); ++i)
std::cout << doubleStr[i] << " ";
std::cout << std::endl;
return 0;
}
There are many ways, but a standard solution is to use std::transform with a lambda using std::to_string for the conversion :
std::transform(std::begin(doubleVec),
std::end(doubleVec),
std::back_inserter(doubleStr),
[](double d) { return std::to_string(d); }
);
And you can wrap that in a function template to make it work with any Standard compliant container :
template<class IteratorIn, class IteratorOut>
void to_string(IteratorIn first, IteratorIn last, IteratorOut out)
{
std::transform(first, last, out,
[](typename std::iterator_traits<IteratorIn>::value_type d) { return std::to_string(d); } );
}
Or in C++14, with a generic lambda :
template<class IteratorIn, class IteratorOut>
void to_string(IteratorIn first, IteratorIn last, IteratorOut out)
{
std::transform(first, last, out, [](auto d) { return std::to_string(d); } );
}
And call it with any container (i.e. it works with std::list<int>, for instance) :
to_string(std::begin(doubleVec), std::end(doubleVec), std::back_inserter(doubleStr));
Notes :
If you don't have a C++11 compiler, write your own to_string function template :
Example:
template<class T>
std::string my_to_string(T v)
{
std::stringstream ss;
ss << v;
return ss.str();
}
And use it in a similar way :
std::transform(doubleVec.begin(),
doubleVec.end(),
std::back_inserter(doubleStr),
my_to_string<double> );
You should reserve() the memory in the output vector to avoid reallocations during std::transform() :
e.g. do this :
std::vector<std::string> stringVec;
stringVec.reserve(v.size()); // reserve space for v.size() elements
Live demo
Using copy and ostream_iterator:
#include <vector>
#include <iostream>
#include <sstream>
#include <iterator>
int main()
{
std::vector<double> numbers{1.0, 2.1, 3.2};
std::stringstream output;
std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<double>(output, " "));
std::cout << output.str() << std::endl;
}
In general, if you have a container of T and want to create a container of U from the container of T, as others have mentioned the algorithm to look for is std::transform.
If you are not using C++ 11, Here is std::transform usage:
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <sstream>
std::string Transformer(double d)
{
std::ostringstream doubleStr;
doubleStr << d;
return doubleStr.str();
}
int main()
{
std::vector<double> doubleVec;
doubleVec.push_back(1.0);
doubleVec.push_back(2.1);
doubleVec.push_back(3.2);
std::vector<std::string> doubleStr;
std::transform(doubleVec.begin(), doubleVec.end(), std::back_inserter(doubleStr), Transformer);
std::copy(doubleStr.begin(), doubleStr.end(), std::ostream_iterator<std::string>(std::cout, " "));
}
Output:
1 2.1 3.2