简体   繁体   中英

Concatenate range of ranges to range

Let rw = ranges::views .

I'm trying to create exclusively using range-v3 an analog of the construction:

std::vector<int> v;

// range = {0, 1, 2}
auto range = rw::ints (0, 3);

for (int i : range)
    for (int j : range)
        v.push_back (func (i, j))

// v = {func (0, 0), func (0, 1), func (0, 2),
//      func (1, 0), func (1, 1), func (1, 2),
//      func (2, 0), func (2, 1), func (2, 2)}

I tried the following option:

// range = {0, 1, 2}
auto range = rw::ints (0, 3);

// range_of_ranges = {{func (0, 0), func (0, 1), func (0, 2)},
//                    {func (1, 0), func (1, 1), func (1, 2)},
//                    {func (2, 0), func (2, 1), func (2, 2)}}
auto range_of_ranges = rw::transform (range, [] (int i) {
    return rw::transform (range, [i] (int j) { return func (i, j); });
});

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::concat (range, range, range);

for (auto x : result)
    printf ("%d\n", x);

But if I replace

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::concat (range, range, range);

with

// result = { {{func (0, 0), func (0, 1), func (0, 2)},
//             {func (1, 0), func (1, 1), func (1, 2)},
//             {func (2, 0), func (2, 1), func (2, 2)}} }
auto result = rw::concat (range_of_ranges);

there will be a compiler warning:

warning: format specifies type 'int' but the argument has type 'ranges::iota_view<int, int>' [-Wformat]
    printf ("%d\n", x);

Unfortunately, it doesn't work and I don't really understand how to fix it properly. I understand that the concat function should take its arguments and combine them into a range and I just created a range of length 1, but I do not know which solution would be correct. Could you give me a hint?

UPD[1] (based on Jarod42 comment: range-v3 has views::cartesian_product ) : It turned out to simplify the code to the following:

auto range = rw::ints (0, 3);

auto cart_prod = rw::cartesian_product (range, range);

auto unpack_args_and_call_func = [] (const auto &arg) {
    return std::apply (func, arg);
};

auto result = rw::transform (cart_prod, unpack_args_and_call_func);

However, using the unpacking argument does not look very nice and convenient.

UPD[2] (based on Jarod42 comment: There are also views::join for your range_of_ranges ) : Replace

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::concat (range, range, range);

with

// result = { {{func (0, 0), func (0, 1), func (0, 2)},
//             {func (1, 0), func (1, 1), func (1, 2)},
//             {func (2, 0), func (2, 1), func (2, 2)}} }
auto result = rw::join (range_of_ranges);

Thanks to Jarod42 .

// range = {0, 1, 2}
auto range = rw::ints (0, 3);

// range_of_ranges = {{func (0, 0), func (0, 1), func (0, 2)},
//                    {func (1, 0), func (1, 1), func (1, 2)},
//                    {func (2, 0), func (2, 1), func (2, 2)}}
auto range_of_ranges = rw::transform (range, [] (int i) {
    return rw::transform (range, [i] (int j) { return func (i, j); });
});

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::join (range_of_ranges);

for (auto x : result)
    printf ("%d\n", x);

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM