0

I'm using range-v3 by Eric Niebler and using the ranges::views::group_by function.

In the documentation for group_by it says: "Given a source range and a binary predicate, return a range of ranges where each range contains contiguous elements from the source range such that the following condition holds: for each element in the range apart from the first, when that element and the first element are passed to the binary predicate, the result is true. In essence, views::group_by groups contiguous elements together with a binary predicate."

So, it returns a range and ranges. My question is how do I access the range of ranges individually? I've tried all the using ways of accessing ranges: p[0].first, p.at(0).first, p.begin.first etc. but no joy.

I have the following code:

#include "https://raw.githubusercontent.com/HowardHinnant/date/master/include/date/date.h"
#include <chrono>
#include <fmt/format.h>
#include <iostream>
#include <map>
#include <range/v3/all.hpp>

using namespace date;

template <typename TimePoint, typename Minutes>
constexpr auto candle_start(const TimePoint timestamp, const Minutes timeframe)
    -> TimePoint {
  using namespace std::chrono;

  const auto time =
      hh_mm_ss{floor<minutes>(timestamp - floor<days>(timestamp))};
  return timestamp - (time.minutes() % timeframe);
}

auto main() -> int {
  {
    using namespace std::chrono;
    using namespace std::chrono_literals;

    const auto tp_now = std::chrono::system_clock::from_time_t(0);

    const auto m =
        std::map<system_clock::time_point, double>{{tp_now + 0min, 1.1},
                                                   {tp_now + 1min, 2.2},
                                                   {tp_now + 2min, 3.3},
                                                   {tp_now + 3min, 4.4},
                                                   {tp_now + 4min, 5.5},
                                                   {tp_now + 5min, 6.6},
                                                   {tp_now + 6min, 7.7},
                                                   {tp_now + 7min, 8.8},
                                                   {tp_now + 8min, 9.9},
                                                   {tp_now + 9min, 10.10},
                                                   {tp_now + 10min, 11.11},
                                                   {tp_now + 11min, 12.12},
                                                   {tp_now + 12min, 13.13},
                                                   {tp_now + 13min, 14.14}};
  
  const auto timeframe = 2min;

  const auto same_candle = [timeframe](const auto &lhs, const auto &rhs) {
    return candle_start(lhs.first, timeframe) ==
           candle_start(rhs.first, timeframe);
  };

  auto p = m
    | ranges::views::reverse 
    | ranges::views::group_by(same_candle);

    // How do I access the range of range values individually?
    std::cout << p[0].first << " = " << p[0].second;

    return 0;
  }

and a play area is given here.

Andrew
  • 626
  • 6
  • 16

1 Answers1

1

p isn't a random access range (it can't be), so there isn't going to be support for indexing (i.e. [0]). And then p isn't a range of pairs, it's a range of range of pairs.

All views have a front() member function that they inherit from view_interface so if you want to print the first and second members of the first subrange of the first range, you can do:

std::cout << p.front().front().first << " = " << p.front().front().second;

Or you can use iterators, as usual.

fmt also supports formatting whole ranges, so if you're looking to just debug, that's probably your best bet:

fmt::print("{}\n", p);

You'll need to include fmt/ranges.h for this support and fmt/chrono.h for chrono-specific formatters.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • thanks the .front is worth knowing. However, when I try using iterators I'm having no joy either. Here's one example of what I'm trying: https://godbolt.org/z/5eax513fP – Andrew Sep 08 '21 at 15:54
  • @Andrew `it` is an iterator, it doesn't have a `.begin()`, it instead is pointing to a range. So it's `(*it).begin()` not `it.begin()`. Also, note the parentheses to control the precedence. https://godbolt.org/z/6nTcPvcYe – Barry Sep 08 '21 at 16:05
  • Thank you. When to use bracket is confusing for me. Thanks again! – Andrew Sep 08 '21 at 16:34
  • Final question. How do I advance the iterators to move through the ranges. This code: https://godbolt.org/z/T16hbxerf isn't working. – Andrew Sep 08 '21 at 18:13
  • @Andrew Did you read what [`std::next`](https://en.cppreference.com/w/cpp/iterator/next) does? – Barry Sep 08 '21 at 19:45
  • thanks so the answer is `it2 = std::next((it2), 2);` – Andrew Sep 08 '21 at 20:28