Search code examples
c++c++17fmt

Format an array with a line break every n values using {fmt}


Using the {fmt} library (the version from github), is there a way to format a long array so that there is a line break inserted after every n values?

For example, say I have a vector of 22 doubles,

std::vector<double> xs {
5.426221e-01, 1.129279e-01, 1.122641e-03, 9.013848e-01,
2.290470e-01, 7.200987e-01, 9.283220e-01, 5.108471e-01,
9.294625e-01, 8.451856e-01, 9.558900e-01, 4.757722e-01,
4.878883e-01, 8.988282e-01, 4.536756e-01, 3.459857e-01,
1.216555e-01, 3.884544e-01, 3.217016e-01, 4.758714e-01,
2.230451e-01, 7.985618e-01
};

fmt::format("{:16.8e}", fmt::join(xs,"")) produces a single line of output. Is there a way to add a delimiter every 5 values, so I can get the following output?

  5.42622100e-01  1.12927900e-01  1.12264100e-03  9.01384800e-01  2.29047000e-01
  7.20098700e-01  9.28322000e-01  5.10847100e-01  9.29462500e-01  8.45185600e-01
  9.55890000e-01  4.75772200e-01  4.87888300e-01  8.98828200e-01  4.53675600e-01
  3.45985700e-01  1.21655500e-01  3.88454400e-01  3.21701600e-01  4.75871400e-01
  2.23045100e-01  7.98561800e-01

Solution

  • C++23

    Use std::views::chunk

    auto const chunks = xs | std::views::chunk(5);
    
    for (auto chunk : chunks) {
        fmt::print("{:16.8e}\n", fmt::join(chunk, ""));    
    }
    

    Demo

    C++17

    Specializing the fmt::formatter struct template according to the official doc.

    template<typename T>
    struct fmt::formatter<std::vector<T>> : fmt::formatter<T>
    {
        auto format(const std::vector<T>& container, format_context& context) const -> format_context::iterator
        {
            auto&& out = context.out();
    
            bool first = true;
            for (int i = 0; i < container.size(); ++i) {
                const auto& elem = container[i];
                if (i % 5 == 0 && i > 0) {
                    format_to(out, "\n");
                }
                fmt::formatter<T>::format(elem, context);
            }
    
            return format_to(out, "");
        }
    };
    

    Demo