重叠时boost :: icl :: interval_map union

时间:2017-11-13 18:45:41

标签: c++ boost

是否可以使interval_map具有以下累积行为:

[1..3]->1 +
[2..4]->2 +
[5..7]->3 +
[6..8]->4
=
[1..4]->{1,2}, [5..8]->{3,4}
+
[3..6]->42
=
[1..8]->{1,2,3,4,42}

1 个答案:

答案 0 :(得分:2)

我认为我以前在一个非常相似的问题上遇到过困难,无法找到图书馆支持的方式。

  

<强> PS 即可。找到帖子boost::multi_index_container, operations on std::set inside container

     

比较有趣,因为它基本上在查询时进行类似的区间合并。这有好处(它保留了插入历史记录,因此您可以查询受益于无损存储的其他结果)。它还可以交换插入效率以获得更高的查询成本。

我可能自己编写插入/组合操作。

我试图在这里提出一个描述性的名字。由于操作感觉类似于将“drop”降落到更大的“池”中,因此我调用了操作mix

template <typename Map, typename V = typename Map::segment_type>
void mix(Map& m, std::initializer_list<V> drops) {
    typename Map::codomain_combine combine;

    for (auto drop : drops) {
        // combine with all overlapping existing segments
        auto range = m.equal_range(drop.first);

        for (auto it = range.first; it != range.second; ++it) {
            combine(drop.second, it->second);
            drop.first = hull(drop.first, it->first);
        }

        m.set(drop); // logically equivalent to m.add(drop) here
    }
}

通过这种方式,您可以表达出您想要的行为:

int main() {
    using Map      = boost::icl::interval_map<int, Ints>;
    using Interval = Map::interval_type::type;
    Map m;

    std::cout << m << "\n";

    mix(m, { {Interval::closed(1,3), {1}},
             {Interval::closed(2,4), {2}},
             {Interval::closed(5,7), {3}},
             {Interval::closed(6,8), {4}} });

    std::cout << m << "\n";

    mix(m, { {Interval::closed(3,6), {42}} }); 

    std::cout << m << "\n";
}

输出将是

{}
{([1,4]->{1,2,})([5,8]->{3,4,})}
{([1,8]->{1,2,3,4,42,})}

完整演示

<强> Live On Coliru

#include <boost/icl/interval_map.hpp>
#include <set>
#include <iostream>

template <typename Map, typename V = typename Map::segment_type>
void mix(Map& m, std::initializer_list<V> drops) {
    typename Map::codomain_combine combine;

    for (auto drop : drops) {
        // combine with all overlapping existing segments
        auto range = m.equal_range(drop.first);

        for (auto it = range.first; it != range.second; ++it) {
            combine(drop.second, it->second);
            drop.first = hull(drop.first, it->first);
        }

        m.set(drop); // logically equivalent to m.add(drop) here
    }
}

// For debug: an ostreamable std::set<int>
struct Ints : std::set<int> {
    using std::set<int>::set;

    friend std::ostream& operator<<(std::ostream& os, Ints const& s) {
        os << '{';
        for(auto i : s) os << i << ",";
        return os << '}';
    }
};

int main() {
    using Map      = boost::icl::interval_map<int, Ints>;
    using Interval = Map::interval_type::type;
    Map m;

    std::cout << m << "\n";

    mix(m, { {Interval::closed(1,3), {1}},
             {Interval::closed(2,4), {2}},
             {Interval::closed(5,7), {3}},
             {Interval::closed(6,8), {4}} });

    std::cout << m << "\n";

    mix(m, { {Interval::closed(3,6), {42}} }); 

    std::cout << m << "\n";
}