This question already has answers here:
How do I print out the contents of a vector?
(31 answers)
Closed 2 years ago.
error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and ‘std::pair<const std::__cxx11::basic_string, std::vector >’)
i want to same key and mutiple values, for example key is 10 values are 2,3,4
but "*iter" is wrong..
how to cout map,vector in c++?
In your code snippet the value of the expression *iter is an object of the type std::pair<std::string, std::vector<int>> for which the operator << is not defined.
And the error message
error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and
‘std::pair<const std::__cxx11::basic_string, std::vector >’)
says about this.
The simplest way is to use the range-based for loop.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <vector>
#include <map>
int main()
{
std::map<std::string, std::vector<int>> m;
m["10"].assign( { 2, 3, 4 } );
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( const auto &item : p.second )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
return 0;
}
The program output is
10: 2 3 4
If you want to write ordinary for-loops using iterators then the loops can look the following way.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <iterator>
int main()
{
std::map<std::string, std::vector<int>> m;
m["10"].assign( { 2, 3, 4 } );
for ( auto outer_it = std::begin( m ); outer_it != std::end( m ); ++outer_it )
{
std::cout << outer_it->first << ": ";
for ( auto inner_it = std::begin( outer_it->second );
inner_it != std::end( outer_it->second );
++inner_it )
{
std::cout << *inner_it << ' ';
}
std::cout << '\n';
}
return 0;
}
Again the program output is
10: 2 3 4
I suggest using structured bindings and range-based for loops:
std::map<std::string,std::vector<int>> m;
for (auto&[str, vec] : m) { // bind str to "first" in the pair and vec to "second"
std::cout << str << ':';
for(auto lineno : vec) std::cout << ' ' << lineno;
std::cout << '\n';
}
You can define how to print things via std::ostream like this:
#include <iostream>
#include <map>
#include <vector>
#include <string>
// define how to print std::pair<std::string, std::vector<int>>
std::ostream& operator<<(std::ostream& stream, const std::pair<std::string, std::vector<int>>& pair) {
stream << "(" << pair.first << ", {";
bool first = true;
for (int e : pair.second) {
if (!first) stream << ", ";
stream << e;
first = false;
}
stream << "})";
return stream;
}
int main(void) {
std::string yytext = "hoge";
int lineno = 42;
// below is copied from the question
std::map<std::string,std::vector<int>> m;
m[yytext].push_back(lineno);
std::map<std::string,std::vector<int>>::iterator iter;
for (iter=m.begin(); iter!=m.end(); iter++){
std::cout<<iter->first<<":"<<*iter<<std::endl;}
}
Related
I'm asking myself if it is possible to extend boost-range by an adaptor, which I call adjacentAdaptor. This adaptor should basically iterate over all pairs of adjacent elements in a vector, list and so on.
I think this function is very useful in my use cases, where I often have to iterate over lists representing time steps.
The output of the last for loop should be something like:
0 1
1 2
2 3
A vector having only one element or no elements should produce nothing.
I tried using boost::adaptors::sliced producing the necessary sublist, but then I don't know how boost::range can help me to zip both subranges to one.
I just found a probable solution using boost::iterators, but I really don't like the amount of code one has to write. Also I'm missing the first and second instead I have to write a clumsy get<>. Unfortunately, the program crashes if the vector is empty!
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
int main()
{
std::vector<int> v = { 0,1,2,3 };
for (auto iter : v | boost::adaptors::sliced(0, v.size() - 1)) {
std::cout << "First: " << iter << std::endl;
}
for (auto iter : v | boost::adaptors::sliced(1, v.size())) {
std::cout << "Second: "<< iter << std::endl;
}
auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.begin(), v.begin() + 1));
auto e = boost::iterators::make_zip_iterator(boost::make_tuple(v.end()-1, v.end()));
for (auto iter : boost::make_iterator_range(s, e)) {
std::cout << iter.get<0>() << " " << iter.get<1>() << std::endl;
}
// for (auto iter : v | adjacentAdaptor) {
// std::cout << iter.first << " " << iter.second << std::endl;
// }
}
I'm very glad for any help I can receive in this question.
Own partial solution
After some template type deduction I came up with something relatively useable.
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
template<typename T>
using retHelperType = decltype(boost::iterators::make_zip_iterator(boost::make_tuple(T().begin(), T().begin() + 1)));
template<typename T>
using retType = decltype(boost::make_iterator_range(retHelperType<T>(), retHelperType<T>()));
template<typename T>
retType<T> adjacentIterator(T& v) {
if (v.empty()) {
auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.end(), v.end()));
auto e = boost::iterators::make_zip_iterator(boost::make_tuple(v.end(), v.end()));
return boost::make_iterator_range(s, e);
}
else {
auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.begin(), std::next(v.begin())));
auto e = boost::iterators::make_zip_iterator(boost::make_tuple(std::prev(v.end()), v.end()));
return boost::make_iterator_range(s, e);
}
}
int main()
{
retType<std::vector<int>> x;
std::vector<int> v = { };
for (auto iter : adjacentIterator(v)) {
std::cout << iter.get<0>() << " " << iter.get<1>() << std::endl;
}
}
Still, it would be nicer to access the elements with first and second, but I have no idea to achieve this behavior.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
void print(vector<string> v) {
for (unsigned int i = 0; i < v.size(); i++) {
cout << "[" << i << "] " << v[i] << "\n";
}
}
int main(){
vector<string> v(5);
v[0] = "Egg";
v[1] = "Milk";
v[2] = "Sugar";
v[3] = "Chocolate";
v[4] = "Flour";
print(v);
system("pause");
}
How do I make a loop that searches for the item, "sugar" and replace it with "honey."? Sry, im new to vectors
If you want to replace the first instance of the string (if it exists) you can use std::find then assign to the iterator that is returned.
std::vector<std::string> v {"Egg", "Milk", "Sugar", "Chocolate", "Flour"};
auto itMatch = std::find(v.begin(), v.end(), "Sugar");
if (itMatch != v.end())
*itMatch = "Honey";
If you'd like to replace all instances
std::replace(v.begin(), v.end(), "Sugar", "Honey");
You can use the standard alfgorithm std::find. For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
int main()
{
std::vector<std::string> v =
{
"Egg", "Milk", "Sugar", "Chocolate", "Flour"
};
const char *src = "Sugar";
const char *dsn = "Honey";
auto it = std::find( v.begin(), v.end(), src );
if ( it != v.end() ) *it = dsn;
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
Egg Milk Honey Chocolate Flour
If you want to replace all occurences of "Sugar" then you can use the standard algorithm std::replace.
For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
int main()
{
std::vector<std::string> v =
{
"Egg", "Milk", "Sugar", "Chocolate", "Flour", "Sugar"
};
const char *src = "Sugar";
const char *dsn = "Honey";
std::replace( v.begin(), v.end(), src, dsn );
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
Egg Milk Honey Chocolate Flour Honey
If you mean the substitution only in the function print within the loop then the function can look the following way
#include <iostream>
#include <vector>
#include <string>
void print( const std::vector<std::string> &v,
const std::string &src = "Sugar",
const std::string &dsn = "Honey" )
{
for ( std::vector<std::string>::size_type i = 0; i < v.size(); i++ )
{
std::cout << "[" << i << "] " << ( v[i] == src ? dsn : v[i] ) << "\n";
}
}
int main()
{
std::vector<std::string> v =
{
"Egg", "Milk", "Sugar", "Chocolate", "Flour"
};
print( v );
return 0;
}
Its output is
[0] Egg
[1] Milk
[2] Honey
[3] Chocolate
[4] Flour
I'm a beginner in c++ and my compiler (c-free 5.0) can't compile this code :-
#include <iostream>
#include <map>
#include <string>
int main()
{
std::string input = "slowly";
std::map<char, int> occurrences;
for (char character : input)
{
occurrences[character] += 1;
}
for (auto& entry : occurrences)
{
std::cout << entry.first << '=' << entry.second << std::endl;
}
}
Can anyone please tell me how to make it work in my compiler ?
Convert the range-based for to loops using iterator
Stop using auto and write the type manually
code:
#include <iostream>
#include <map>
#include <string>
int main()
{
std::string input = "slowly";
std::map<char, int> occurrences;
for (std::string::iterator character = input.begin(); character != input.end(); character++)
{
occurrences[*character] += 1;
}
for (std::map<char, int>::iterator entry = occurrences.begin(); entry != occurrences.end(); entry++)
{
std::cout << entry->first << '=' << entry->second << std::endl;
}
}
I want to change all the words stored in a map to lower case. with lambda function and transform, how should I do that?
std::map <string, int> M;
std::map<string, int> M1;
std::transform(M.begin(), M.end(), M1.begin(),
[](pair<const string, int> const & p) { ::tolower(p.first); });
You can't edit keys in a map, so you'll have to create a new map
Something along the lines of:
iterate over the values in your map
take a copy of the key
transform it to lowercase
insert it into your result map:
Example:
#include <iostream>
#include <map>
#include <algorithm>
int main()
{
std::map<std::string, int> map = {{ "HELLO", 1 }, { "WORLD", 2 }};
std::cout << "before:\n";
for (auto& kv : map)
{
std::cout << '\t' << kv.first << ":" << kv.second << '\n';
}
// create a new map with lowercase keys
std::map<std::string, int> out;
std::for_each(map.begin(), map.end(), [&](auto& kv)
{
std::string lower;
std::transform(kv.first.begin(), kv.first.end(), std::back_inserter(lower), tolower);
out[lower] = kv.second;
});
std::cout << "after:\n";
for (auto& kv : out)
{
std::cout << '\t' << kv.first << ":" << kv.second << '\n';
}
return 0;
}
output:
before:
HELLO:1
WORLD:2
after:
hello:1
world:2
std::transformassigns the result of the functor to elements in the destination range. This means that the destination iterator must be the start of range with same size as the input range. In your example, the destination is an empty map. The transform essentially is the following loop:
std::map <string, int> M;
std::map<string, int> M1;
for(auto i=M.begin(), j=M1.begin(); i != M.end(); ++i,++j)
{
*j = f(*i);
}
Decrementing j is illegal for empty containers, and doesn't really make sense for a map since you cannot change the key.
What you can see from this code is that your lambda is also incorrect. It should transform one (key value) pair into an object of the target type. In your case, the target type is the same.
You either have to resize the destination container before, e.g. by calling resize if it was a vector, or use an iterator which adapts the assignment to map::insert. The STL provides adaptors for this:
#include <map>
#include <string>
#include <cctype>
#include <iterator>
#include <algorithm>
int main() {
std::map <std::string, int> M;
std::map<std::string, int> M1;
std::transform(M.begin(), M.end(), std::inserter(M1, M1.begin()),
[](std::pair<const std::string, int> const & p)
{
std::string lowercase;
std::transform( p.first.begin(), p.first.end(),
std::back_inserter(lowercase),
[](auto c) {return std::tolower(c);} );
return std::make_pair(lowercase, p.second);
});
return 0;
}
If you want to use exactly std::transform then you can use the following approach
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <cctype>
#include <iterator>
#include <utility>
int main ()
{
std::map<std::string, int> m1 = { { "FIRST", 1 }, { "SECOND", 2 } };
for ( const auto &p : m1 )
{
std::cout << p.first << '\t' << p.second << std::endl;
}
auto to_lower_case = []( const std::pair<const std::string, int> &p )
{
std::string t; t.reserve( p.first.size() );
std::transform( p.first.begin(), p.first.end(),
std::back_inserter( t ), ::tolower );
return std::make_pair( t, p.second );
};
std::cout << std::endl;
std::map<std::string, int> m2;
std::transform( m1.begin(), m1.end(),
std::inserter( m2, m2.begin() ), to_lower_case );
for ( const auto &p : m2 )
{
std::cout << p.first << '\t' << p.second << std::endl;
}
}
The program output is
FIRST 1
SECOND 2
first 1
second 2
In the program there are used std::transform two times.
I am looking for a fastest way to convert a byte array of arbitrary length to a hexadecimal string. This question has been fully answered here at StackOverflow for C#. Some solutions in C++ can be found here.
Are there any "turnkey" or "ready-made" solutions to a problem? C-style solutions are welcome.
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
#include <sstream>
#include <iomanip>
int main()
{
std::vector<unsigned char> v;
v.push_back( 1 );
v.push_back( 2 );
v.push_back( 3 );
v.push_back( 4 );
std::ostringstream ss;
ss << std::hex << std::uppercase << std::setfill( '0' );
std::for_each( v.cbegin(), v.cend(), [&]( int c ) { ss << std::setw( 2 ) << c; } );
std::string result = ss.str();
std::cout << result << std::endl;
return 0;
}
Or, if you've got a compiler that supports uniform initialization syntax and range based for loops you can save a few lines.
#include <vector>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::vector<unsigned char> v { 1, 2, 3, 4 };
std::ostringstream ss;
ss << std::hex << std::uppercase << std::setfill( '0' );
for( int c : v ) {
ss << std::setw( 2 ) << c;
}
std::string result = ss.str();
std::cout << result << std::endl;
}
Use boost::alogorithm::hex
std::vector<unsigned char> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::string res;
boost::algorithm::hex(v.begin(), v.end(), back_inserter(res));
You can use the C++ Standard Library and or you can use boost::lexical_cast
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <sstream>
#include <iomanip>
#include <algorithm>
using namespace std;
// use this macro for c++11 feature
#define USE_CPP11
int main(int argc, char* argv[])
{
array<unsigned char, 3> hexArr = {0x01, 0xff, 0x55};
const char separator = ' '; // separator between two numbers
ostringstream os;
os << hex << setfill('0'); // set the stream to hex with 0 fill
#ifdef USE_CPP11
std::for_each(std::begin(hexArr), std::end(hexArr), [&os, &separator] (int i)
{
os << setw(2) << i << separator;
});
#else // c++03
typedef array<unsigned char, 3>::const_iterator const_iterator;
for (const_iterator it = hexArr.begin(); it != hexArr.end(); ++it)
{
os << setw(2) << int(*it) << separator;
}
#endif
os << dec << setfill(' '); // reset the stream to "original"
// print the string
cout << "the string array is: " << os.str() << endl;
return EXIT_SUCCESS;
}
One of the fastest way I know in C++ 11:
template <size_t byteCount>
string BytesArrayToHexString( const std::array<byte, byteCount>& src )
{
static const char table[] = "0123456789ABCDEF";
std::array<char, 2 * byteCount + 1> dst;
const byte* srcPtr = &src[0];
char* dstPtr = &dst[0];
for (auto count = byteCount; count > 0; --count)
{
unsigned char c = *srcPtr++;
*dstPtr++ = table[c >> 4];
*dstPtr++ = table[c & 0x0f];
}
*dstPtr = 0;
return &dst[0];
}
A good compiler should not have any problem to apply SSE optimization on this....