I'm given a CSV file with two elements per line:
1,2
12,40
11,7
...
which I want to read into a std::map<int, int>
.
How can I do that, using anything from Ranges library and Range-v3 ?
At the moment this is where I've got (with the help of this answer ):
#include <boost/hof/lift.hpp>
#include <iostream>
#include <range/v3/istream_range.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/istream.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/chunk.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/split.hpp>
#include <string>
using ranges::istream;
using ranges::to;
using namespace ranges::views;
constexpr auto splitAtComma = [](auto const& r) { return r | split(','); };
constexpr auto rngToString = [](auto const& r) { return r | to<std::string>; };
constexpr auto strToInt = BOOST_HOF_LIFT(std::stoi);
constexpr auto parseCoords = transform(splitAtComma)
| join
| transform(rngToString)
| transform(strToInt)
| chunk(2);
int main() {
auto lines = istream<std::string>(std::cin);
auto coords = lines | parseCoords;
std::cout << coords << std::endl;
}
which, invoked like this
./main <<END
1,2
12,40
11,7
END
gives this output
[[1,2],[12,40],[11,7]]
The point is that now I don't know how convert that range-of-ranges into a map. Also, I have the feeling that I'm in a dead-end street, because each element of a std::map<int, int>
comes from 2 int
s, but in the range-of-ranges above [1,2]
, [12,40]
, and [11,7]
are just ranges of int
s, not encoding at compile tiime that there's 2 int
s only.
There is no need to use join
here because r | split(',')
r | split(',')
already gives you a range with two elements. Prefer std::from_chars
over std::stoi
.
You can do this only using the standard library's <ranges>
#include <ranges>
#include <charconv>
#include <fmt/ranges.h>
#include <sstream>
auto toInt = [](auto r) {
int i = 0;
std::from_chars(std::to_address(r.begin()), std::to_address(r.end()), i);
return i;
};
auto parseCoords =
std::views::transform(
[](auto r) { return std::move(r) | std::views::split(','); })
| std::views::transform(
[](auto r) { return std::pair{toInt(r.front()), toInt(*++r.begin())}; });
int main() {
auto in = std::istringstream{R"(
1,2
12,40
11,7
)"};
auto coords = std::views::istream<std::string>(in)
| parseCoords;
fmt::print("{}\n", coords);
}
Note that the std::move(r)
in views::transform
is necessary because we need to construct an owning_view
to avoid the dangling issue.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.