Home > Back-end >  C construct a map with two ranges
C construct a map with two ranges

Time:11-15

Is there a way to construct a map with two ranges in C ? That is, instead of calling a default constructor and consequently inserting elements to a map:

for (size_t i = 0; i < Vector_1.size() && i < Vector_2.size(); i  ) {
    mymap[Vector_1[i]] = Vector_2[i];
}

I'd like to build a map in place by calling some sort of a constructor which would take two ranges as arguments, something like this:

std::map<t1, t2> mymap(Vector_1.begin(), Vector_1.end(), Vector_2.begin(), Vector_2.end());

Or:

mymap.insert(Vector_1.begin(), Vector_1.end(), Vector_2.begin(), Vector_2.end());

I haven't found any, but maybe there is still a way to do it. Is there a shortcut to initialize a map from two ranges, or at least insert two ranges into a map?

CodePudding user response:

You could use Eric Niebler's range-v3 library, zip the two vectors in a view, and write that view out to a map.

[Demo]

#include <fmt/ranges.h>
#include <map>
#include <range/v3/all.hpp>
#include <vector>

int main() {
    std::vector<char> cs{'a', 'b', 'c'};
    std::vector<int> is{1, 2, 3};
    auto m{ ranges::views::zip(cs, is) | ranges::to<std::map<char, int>>() };
    fmt::print("{}", m);
}

// Outputs: {'a': 1, 'b': 2, 'c': 3}

As Armin Montigny indicated, the std::ranges::views::zip won't be available until C 23; and the same happens with std::ranges::to. Here you can see some compilers already implement std::ranges::views::zip but not yet std::ranges::to.

CodePudding user response:

Is there a shortcut to initialize a map from two ranges, or at least insert two ranges into a map?

It is straightforward to create your own "shortcut", which typically takes the form of a free function.

#include <cassert>
#include <vector>
#include <list>
#include <map>
#include <ranges>
#include <iostream>

template <std::ranges::range K, std::ranges::range V>
std::map<std::ranges::range_value_t<K>, std::ranges::range_value_t<V>> createMapFromRanges(K&& krng, V&& vrng)
{
    std::map<std::ranges::range_value_t<K>, std::ranges::range_value_t<V>> map;
    assert(std::size(krng) == std::size(vrng));
    auto [k, kend] = std::tuple{krng.begin(), krng.end()};
    auto [v, vend] = std::tuple{vrng.begin(), vrng.end()};
    while (k != kend && v != vend)
        map.emplace(*k  ,*v  );
    return map;
}
    
int main()
{
    auto map = createMapFromRanges(std::vector<int>{1,2,3}, std::list<int>{4,5,6});
    for (auto& elem : map) {
        std::cout << elem.first << '/' << elem.second << '\n';
    }
    return 0;
}

P.S. I see many posts referencing other libraries (e.g. boost, range-v3) or unsupported features (e.g. zip_view). Certainly, I am in favor of reusing high quality libraries. Unfortunately, many projects simply cannot use them (i.e. restricted by the organization).

  • Related