I have a vector of OpenCV points and want to print 20 of them per line.
The following code works, but I don't like that it needs to create intermediate vectors.
const std::vector<cv::Point> points { .... };
fmt::print("20 points per line:\n{}",
points | ranges::views::transform([](const auto& point) {
return fmt::format("({}, {})", point.x, point.y);
})
| ranges::views::chunk(20)
| ranges::views::transform([](const auto& chunk) {
// really ugly
return chunk | ranges::to<std::vector<std::string>>;
})
// but how can I do this otherwise?
| ranges::views::intersperse(std::vector<std::string>{"\n"})
| ranges::views::join
| ranges::views::join
| ranges::to<std::string>);
Can I somehow intersperse a linebreak every 20 strings by directly specifying that this is supposed to be a range of the same type, or otherwise get around the intermediate to<vector<string>>
?
What doesn't work, for reasons I don't understand, is just using
| ranges::views::intersperse(ranges::view::single(std::string{"\n"}))
directly after the chunk.
You can use concat view instead.
https://godbolt.org/z/WYoqr1z9G
std::string result = points
| ranges::views::transform([](auto&& point) {
return fmt::format("({}, {})"sv, point.x, point.y);
})
| ranges::views::chunk(5)
| ranges::views::transform([](auto&& chunk) {
return ranges::views::concat(chunk | ranges::views::join, "\n"sv);
})
| ranges::views::join
| ranges::to<std::string>;
EDIT
As in what I was mentioning in comment, is about C++23 implementation of interparse -- join_with; godbolt
auto result = points
| ranges::views::transform([](auto&& point) {
return fmt::format("({}, {})"sv, point.x, point.y);
})
| ranges::views::chunk(5)
| ranges::views::transform([](auto&& chunk) {
return chunk | ranges::views::join | ranges::to<std::string>();
})
| ranges::views::join_with("\n"sv)
| ranges::to<std::string>();
If someone knows how to flatten a chunk_view to string_view compatible without allocating additional string copies that is much appreciated.