Python's enumerate for C++ [duplicate] - c++

This question already has answers here:
How to find the index of current object in range-based for loop?
(12 answers)
Closed 4 years ago.
In Python there is enumerate which takes a sequence/iterator and yields pairs of an integer index and the value itself. In C++ I occasionally find myself writing
for (size_t i = 0; i != vector.size(); ++i) {
auto const &elem = vector[i];
// ...
Similar to Python I would like to write
for (auto const &it : enumerate(vector)) {
// it.first is the index (size_t)
// it.second is the element (T const&)
Does such an enumerate exist in either the STL or a common library like Boost?

Yes, this is what Boost's adapators::indexed does.
Their example (which also uses the now-redundant Boost.Assign for terse container initialisation) follows:
#include <boost/range/adaptor/indexed.hpp>
#include <boost/assign.hpp>
#include <iterator>
#include <iostream>
#include <vector>
int main(int argc, const char* argv[])
{
using namespace boost::assign;
using namespace boost::adaptors;
std::vector<int> input;
input += 10,20,30,40,50,60,70,80,90;
for (const auto& element : input | indexed(0))
{
std::cout << "Element = " << element.value()
<< " Index = " << element.index()
<< std::endl;
}
return 0;
}
Nothing in the standard library, though it's not hard to write.

Here is an example using range-v3. A bit more verbose than a handcrafted solution, but it's nice IMHO how you can assemble such a range from existing views.
#include <range/v3/view/indices.hpp>
#include <range/v3/view/zip.hpp>
using namespace ranges;
std::vector<int> vec{42, 43, 44};
for (const auto& idxAndValue : view::zip(view::indices, vec))
std::cout << ideAndValue.first << " : " << idxAndValue.second << "\n";;

Another way that only works:
with references to elements, and
array-based containers, and
elements do not overload operator&
for(auto const &it : vector) {
size_t index = &it - vector.data();
}

Here's a version using an higher-order function. I like it because it's simple to implement and doesn't require you to know the nuances of structured bindings. It also doesn't require any extra dependency.
template <typename Container, typename F>
void enumerate(Container&& c, F&& f)
{
std::size_t i = 0;
for(auto&& x : std::forward<Container>(c))
{
f(i++, forward_like<Container>(x));
}
}
(Where forward_like moves x if Container is an rvalue.)
Usage:
enumerate(std::vector{'a', 'b', 'c'}, [](auto index, auto x)
{
std::cout << index << ": " << x << '\n';
});
Prints:
0: 'a'
1: 'b'
2: 'c'
live example on wandbox.org
C++11 compliant version: live example on wandbox.org

Related

Is it possible to put lambda expressions into a map or list in C++?

#DanielLangr #luxun #cdhowie sorry for the XY problem. i am not sure i can explain well, but i try my best. the situation is almost like this: there is a base object "Worker" and some children. chef、tailor... children has the same action like walk、run、sleep...but different skill,chef can make food, tailor can Make clothes. Invoker call Worker dothings but do not exactly know their profession.so i add a interface dothings(Thing) on Worker the base object. Thing is an enum,value is MakeFood、MakeClothes...
Worker *w = new Chef();
w->dothings(MakeFood);//
w->dothings(MakeClothes);//throw exception "w do not have skill"
so i think meybe use a container in children that describe what it can do and how to do.
hope i explained clearly.and is there a better solution?
I want to put different lambda expressions into a list or Qmap, like below.
Qmap<String, lambda> map;
map.insert("first",[](int i) -> int {return i;});
map.insert("second",[](string s) -> string {return s;});
Is it possible in C++? And what is the type of lambda?
It is possible but using function wrapper.
For example,
std::map<std::string, std::function<void(std::string)>> my_map;
my_map.emplace("first", [](std::string i) { std::cout << i << std::endl; });
However, if you want to pass any type of argument to your function and return any type from your lambda/function, use boost::any. You also use std::any if you are using C++17 or above.
EDIT:
A working example:
#include <iostream>
#include <string>
#include <functional>
#include <map>
#include <boost/any.hpp>
int main()
{
auto any = [](boost::any i)
{
std::cout << "In any" << std::endl;
if (i.type() == typeid(int))
std::cout << boost::any_cast<int>(i) << std::endl;
return boost::any(1000);
};
std::map<std::string, std::function<boost::any(boost::any)>> my_map;
my_map.emplace("first", any);
my_map.emplace("second", [](boost::any i) -> boost::any { });
auto ret = my_map["first"](100);
std::cout << boost::any_cast<int>(ret) << std::endl;
return 0;
}
Outputs:
In any
100
1000
With any, the solution may look like as follows:
auto lambda1 = [](int i) { return i; };
auto lambda2 = [](std::string s) { return s; };
std::map<std::string, std::any> map;
map["first"] = lambda1;
map["second"] = lambda2;
std::cout << std::any_cast<decltype(lambda1)>(map["first"])(-1) << std::endl;
std::cout << std::any_cast<decltype(lambda2)>(map["second"])("hello") << std::endl;
I am not familiar with Qmap and String, so I used the types from the C++ Standard Library.
Live demo: https://godbolt.org/z/8XK8de
Alternatively, you can also additionally use std::function if you want to avoid those decltypes:
std::map<std::string, std::any> map;
map["first"] = std::function<int(int)>( [](int i) { return i; } );
map["second"] = std::function<std::string(std::string)>( [](std::string s) { return s; } );
std::cout << std::any_cast<std::function<int(int)>>(map["first"])(-1) << std::endl;
std::cout << std::any_cast<std::function<std::string(std::string)>>(map["second"])("hello") << std::endl
Live demo: https://godbolt.org/z/XAc3Q2
However, as other pointed out to, this really seems to be an XY problem.
It is possible as long as you are trying to insert the same lambda type ( your example has different lambda types) You have to be careful how you do it but it does work. For example
#include <iostream>
#include <map>
int main(){
auto factory = [](int i){
return [=](int j){return i+j;};
};
using L = decltype(factory(0));
std::map<int,L> map;
map.emplace(0,factory(0));
map.emplace(7,factory(7));
std::cout << map.at(0)(3) << std::endl ;
std::cout << map.at(7)(3) << std::endl ;
}
outputs
3
10
as expected and not a std::function in sight! However the following does not work
#include <iostream>
#include <map>
int main(){
auto factory = [](int i){
return [=](int j){return i+j;};
};
using L = decltype(factory(0));
std::map<int,L> map;
map[0]=factory(0);
map[7]=factory(7);
std::cout << map[0](3) << std::endl ;
std::cout << map[7](3) << std::endl ;
}
Using the indexing operator tries to use copy assignment whereas emplace doesn't.
https://godbolt.org/z/co1vno6xb

How to check if elements of std::vector<std::string> start with certain sub-string?

I have a very large std::vector v of type std::vector<std::string> v. Now I want to compare which of the elements in the vector start with a certain substring str. What is the fastest possible way to do that?
I was thinking of a for-loop that iteratively compares the start of each element of v with the substring str. I first tried
std::string substring = "bla";
for (long unsigned int i = 0; i < v.size(); i++)
{
if (!strncmp(v[i].c_str(), substring.c_str(), substring.size()))
{
std::cout << "Item found: " << v[i] << std::endl;
}
}
Which is c mixed with c++ and I am not happy with that.
What better alternatives are there?
You can write completely a c++ code.
If you want to find all the elements satisfying the condition, you can not avoid iterating through the entire vector.
But you could use better range-based for-loop instead of index based loop to iterate through the vector, and check wether str.find(substring) == 0(credits #PiotrSkotnicki).
Here is the example code:
(See online)
#include <iostream>
#include <string>
#include <vector>
int main()
{
const std::string substring{ "bla" };
std::vector<std::string> vecString{ {"bllll"}, {"bllll"}, {"blasomething"} };
// iterate through the vector by range based for-loop
// here `auto` deduded to `std::string` as you have vector of strings(i.e. `vecString`)
for (const auto& str : vecString)
{
if (str.find(substring) == 0) {
std::cout << str << " is a match\n";
// do something more with str
}
}
return 0;
}
Alternatively using std::for_each, along with a lambda function you could write the following. Read more about the lambdas here: What is a lambda expression in C++11?
(See online)
#include <algorithm> // std::for_each
std::for_each(std::cbegin(vecString), std::cend(vecString), [&substring](const auto& str)
{
if (str.find(substring) == 0)
{
std::cout << str << " is a match\n";
// do something more with str
}
});
If you are interested only the first match in the vector of string s, making use of standard algorithm std::find_if as follows
#include <algorithm> // std::find_if
const auto iter = std::find_if(std::cbegin(vecString), std::cend(vecString),
[&substring](const auto& str) {
return str.find(substring) == 0;
}
);
if (iter != std::cend(vecString))
{
// do something
}
If you have an unsorted container you can't get better than O(n) in time complexity, which means iterating over the whole container in a linear manner (i.e. for loop). If your container was sorted (ex. std::set instead of std::vector) you would get O(log n) which is a lot better (binary search).
Prior to C++17, I can't come up with a better solution than yours (since creating a substring via std::string::substr means copying the substring unnecessarily). However C++17 introduced std::string_view which doesn't do any copying. There should be no noticable performance difference with compiler optimizations enabled.
std::vector<std::string> v { "abcd", "abcdefg", "aaaabbbb", "abc", "ab"};
std::string_view query = "abc";
for (auto const& str : v)
{
if (str.size() < query.size())
continue;
auto probe = std::string_view(str).substr(0, query.size());
if (query == probe)
std::cout << "Item found: " << str << "\n";
}
Live example
And here is the std::set version for the quicker search:
std::set<std::string> v { "abcd", "abcdefg", "aaaabbbb", "abc", "ab"};
std::string query = "abc";
for (auto it = v.lower_bound(query); it != v.end(); ++it)
{
auto probe = std::string_view(*it).substr(0, query.size());
if (query == probe)
std::cout << "Item found: " << *it << "\n";
else
break;
}
Live example
You can using c++20 std::string_view::start_with:
std::vector<std::string> v = {...};
std::string_view prefix = "bla";
for (std::string_view sv : v)
if (sv.starts_with(prefix))
std::cout << "Item found: " << sv << std::endl;

How to write API for insertion and erase functionality of multimap?

I am implementing a replacement container library which stores value of any type in some sorted manner, I need to write API in C++ to get the Sorted functionality by using equivalent boost functionality (multimap).
I am working in a project called RogueWave library replacement, and I need to implement functionality of RWTValSortedVector functionality using the Boost library. I need to write the API for this class using Boost library code.
These two things I needed to implement it in Boost.
insert(const_reference a)
remove(const_reference a)
The reference link for RWTValSortedVector is, https://docs.roguewave.com/sourcepro/11/html/toolsref/rwtvalsortedvector.html
I need this equivalent boost API for that functionality.
Here I mentioned my code snippet formats,
boost::container::multiset<data type, less<data_type> > vec;
vec.insert(data_type("value"));
vec.insert(data_type("value"));
//for erase method
vec.erase(data_type("value"));
I need to write container library API which stores value of any type in some sorted manner. Anyone please help me to resolve this.
Looking up the actual documentation for remove:
Removes the first element t in self such that the expression (t == a) is true and returns true. Returns false if there is no such element.
So, this would be a start:
Live On Coliru
#include <boost/container/flat_set.hpp>
#include <string>
template <typename T>
struct SortedVec {
boost::container::flat_multiset<T> _data;
auto begin() const { return _data.begin(); }
auto end() const { return _data.end(); }
bool insert(T value) {
_data.emplace(std::move(value));
return true;
}
auto erase(T const& key) {
auto r = _data.equal_range(key);
if (r.first == r.second)
return false;
_data.erase(r.first);
return true;
}
};
#include <iostream>
#include <iomanip>
int main() {
SortedVec<std::string> vec;
vec.insert("zz");
vec.insert("value");
vec.insert("value");
vec.insert("aa");
std::cout << "Before erase:";
for (auto& s : vec) std::cout << " " << std::quoted(s);
assert(vec.erase("value"));
std::cout << "\nAfter 1 erase:";
for (auto& s : vec) std::cout << " " << std::quoted(s);
assert(vec.erase("value"));
std::cout << "\nAfter 2 erases:";
for (auto& s : vec) std::cout << " " << std::quoted(s);
assert(!vec.erase("value"));
}
Prints
Before erase: "aa" "value" "value" "zz"
After 1 erase: "aa" "value" "zz"
After 2 erases: "aa" "zz"

Adjacent adaptor using boost::range

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.

I want to reverse the values of map and print it using range based for loop.

I have done the programming but it is not reversing. I have used a different map to put the values in reverse order,but it still shows the same. My main question was to traverse backward and print the values using range based loop.
#include "stdafx.h"
#include <iostream>
#include<conio.h>
#include <stdio.h>
#include<vector>
#include<map>
#include<utility>
#include<set>
map<int, int>m1;
for (int i = 1; i <= 100; ++i)
{
m1.insert({ i,i });
}
for (const auto &y :m1)
{
cout <<"("<< y.first << " "<<y.second << ")" <<" " ;
}
cout << endl << endl;
map<int, int>m2;
map<int, int>::reverse_iterator iter;
for (auto iter = m1.rbegin(); iter != m1.rend(); ++iter)
{
m2.insert({ iter->first,iter->second });
}
for (const auto &y : m2)
{
cout << "(" << y.first << " " << y.second << ")" << " ";
}
As Some Programmer Dude pointed out, but for the completeness of my answer, a std::map is sorted on the key, no matter what order you insert the elements. One option would be to create a new map with the opposite sorting, but that doesn't seem to be what you really want.
It seems you know how about reverse iterators, but not how to get at them when using range-based for. Since it operates on a range, i.e. some type that provides begin and end iterators, you need to create some wrapper around your map that provides this.
Here's a general one I just put together than works in C++11. It won't cover every possible case, and can be made a bit neater in C++14, but it will work for you.
#include <iostream>
#include <iterator>
// The wrapper type that does reversal
template <typename Range>
class Reverser {
Range& r_;
public:
using iterator_type = std::reverse_iterator<decltype(std::begin(r_))>;
Reverser(Range& r) : r_(r) {}
iterator_type begin() { return iterator_type(std::end(r_)); }
iterator_type end() { return iterator_type(std::begin(r_)); }
};
// Helper creation function
template <typename Range>
Reverser<Range> reverse(Range& r)
{
return Reverser<Range>(r);
}
int main()
{
int vals[] = {1, 2, 3, 4, 5};
for (auto i : reverse(vals))
std::cout << i << '\n';
}
This outputs:
$ ./reverse
5
4
3
2
1
(You may also find libraries that provide a similar adapter; Eric Niebler is working on a ranges library for The Standard.)
Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).
Here's an example of iterating backward through a std::map:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<int, int> m;
m[1] = 1;
m[2] = 2;
m[3] = 3;
for (auto iter = m.rbegin(); iter != m.rend(); ++iter) {
std::cout << iter->first << ": " << iter->second << std::endl;
}
}
If you are pre-C++11, you'll just need to spell out auto, which is:
std::map<int, int>::reverse_iterator
If you're using boost, you can use a range-based for loop with a reverse adapter:
#include <boost/range/adaptor/reversed.hpp>
for (auto& iter : boost::adaptors::reverse(m)) {
std::cout << iter.first << ": " << iter.second << std::endl;
}
If you only need to print the elements in the map in reverse order,you don't need another map for it,you can do this:
std::map<int, int>::reverse_iterator iter;
for (iter = m1.rbegin(); iter != m1.rend(); ++iter)
{
std::cout << "(" << iter->first << " " << iter->second << ")" << " ";
}