Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repeat contents of a std::vector

Suppose I have a vector (potentially large) of trivial types, e.g.

std::vector<int> v{1,2,3};

What is the best way to repeat it n times?

E.g. 3 times would give the result {1,2,3,1,2,3,1,2,3}

Surely, this is a problem that arises often (numeric libraries usually have such a function build in). My naive solution:

template<typename T>
std::vector<T> repeat(const std::vector<T> &input, unsigned int times) {
    std::vector<T> result;
    auto input_size = input.size();
    result.reserve(input_size * times);
    for (std::size_t rep = 0; rep < times; ++rep) {
        for (std::size_t i = 0; i < input_size; ++i) {
            result.push_back(input[i % input_size]);
        }
    }
    return result;
}

Surely this can be made faster? Maybe with std::copy? In that case, however, I'm not sure how to tell the vector its new size while avoiding zero-initialization. Apparently it cannot be done easily (see, e.g., 1). I tried to do it with iterators as well, but it didn't seem to be faster.

like image 578
Adomas Baliuka Avatar asked Oct 15 '25 18:10

Adomas Baliuka


2 Answers

With range-v3 you could write:

#include <range/v3/all.hpp>
namespace rv = ranges::views;

template<typename T>
auto repeat(const std::vector<T> &input, unsigned int times) 
{
    return rv::repeat_n(input, times) 
           | rv::join 
           | ranges::to<std::vector<T>>;
}

Here's a demo.

I suspect this will have sufficiently good performance for your needs.

like image 84
cigien Avatar answered Oct 18 '25 07:10

cigien


I would just immediately size the vector to avoid any intermediate re-allocations. Then you can use std::copy with some arithmetic to copy the input vector into result using specific offsets into that pre-allocated vector.

template<typename T>
std::vector<T> repeat(const std::vector<T> &input, unsigned int times) {
    std::vector<T> result(input.size() * times);
    for (std::size_t rep = 0; rep < times; ++rep) {
        std::copy(input.begin(), input.end(), std::next(result.begin(), rep * input.size()));
    }
    return result;
}
like image 36
Cory Kramer Avatar answered Oct 18 '25 07:10

Cory Kramer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!