How to generate vector like list comprehension

15,328

Solution 1

Do you want to use third-party libraries? Eric Niebler's range-v3 allows for:

std::vector<string> blockPathList =
        view::ints(0, blockNum)
        | view::transform([&desPath](int i) {
            return desPath + "part" + std::to_string(i);
        });

That's about as functional list-comprehension-y as you're going to get in C++.

Solution 2

Not pretty either, but should also get the job done:

int cur = 0;
std::vector<std::string> blockPathList(blockNum);
std::generate(blockPathList.begin(), blockPathList.end(),
        [&](){ return destPath + "part" + std::to_string(cur++); });

Unfortunately this

  • Requires the vector to be pre-sized
  • Requires an external iteration variable (since the std::generate Generator does not take any arguments.

You can also use std::for_each:

std::vector<int> nums(blockNum);
std::iota(nums.begin(), nums.end(), 0);
std::for_each(nums.begin(), nums.end(), [&](int c) {
        blockPathList.push_back(destPath + "part" + std::to_string(c));
        });

but again this is uglified because std::iota doesn't generate ranges. It populates an existing range with an iterator, rather than acting as a numeric iterator in-itself (of course you can solve that by implementing or using something which generates those iterators)

Solution 3

Another example (c++14):

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

template<typename CONTAINER, typename LAMBDA>
auto comprehension(CONTAINER&& container, LAMBDA&& lambda){
      std::vector<decltype(lambda(*container.begin()))> w;
      std::transform(container.begin(),container.end(),std::back_inserter(w), lambda);
      return w;
}
int main(){
    auto&& ints = {1,2,3,4,5};
    auto&& squares = comprehension(ints,[](auto i){ return i*i; });

    for( auto s : squares){ std::cout << s << ' '; }
    std::cout << '\n';
}

Output:

1 4 9 16 25
Share:
15,328

Related videos on Youtube

chenzhongpu
Author by

chenzhongpu

Updated on September 14, 2022

Comments

  • chenzhongpu
    chenzhongpu over 1 year

    In C++11,

    vector<string> blockPathList;
    for(int i = 0; i < blockNum; i++)
    {
        blockPathList.push_back(desPath + "part" + to_string(i));
    }
    

    Is it possible to re-write the code above like list comprehension, or shorter and more concise?

    • Vincent Savard
      Vincent Savard almost 8 years
      @ChenZhongPu: My point is those information should be in your question so it can be answered appropriately. Read more about minimal reproducible example.
    • ForceBru
      ForceBru almost 8 years
      Does C++ support list comprehensions? You're probably looking for Haskell or Python
    • Mark Nunberg
      Mark Nunberg almost 8 years
      Is std::generate something you'd be interested in (though in this case you'd need to pre-size the vector)?
    • Vincent Savard
      Vincent Savard
      What's blockNum and desPath?
    • Carcigenicate
      Carcigenicate
      It looks like you're turning 1 type of list (vector) into another. This seems like a job for a map function, which I'm fairly sure C++ has.
  • Max Lybbert
    Max Lybbert almost 8 years
    You don't have to pre-size the vector if you use generate_n (C++11) and back_inserter.