提升`interval_map` - 如何在触摸时自定义聚合

时间:2018-06-13 23:41:36

标签: c++ boost-icl

Boost ICL interval_set可以加入右开区间,互相接触,将它们添加到集合中。例如,时间间隔[0,4)[4,8)将合并为一个时间间隔[0,8)

对于interval_map - 间隔来说,这更复杂,它们相互接触并具有不同的关联值,不会加入:

#include <iostream>
#include <utility>

#include <boost/icl/interval_map.hpp>

namespace icl = boost::icl;

using IMap = icl::interval_map<int, int>;

int main()
{
  IMap m;
  m += std::make_pair(IMap::interval_type::right_open(0, 4), 1);
  m += std::make_pair(IMap::interval_type::right_open(4, 8), 2);
  std::cout << m << std::endl;
}

此测试程序的输出如下:

{([0,4)->1)([4,8)->2)}

我知道如何自定义重叠聚合的过程,但我需要自定义另一个案例 - 在触摸时聚合。例如,如果间隔相互接触左侧间隔的值等于右侧间隔减1 的值,则必须连接间隔,并产生间隔必须具有左间隔的值。所以,上面的程序应该打印:

{([0,8)->1)}

是否可以使用当前可用的Boost ICL进行此操作?

我可以使用interval_map进行奇怪的操作来做我想做的事情,但我认为它很麻烦且效率低下。我更倾向于指出正确的方向使用目前可用的ICL自定义,仿函数等。

1 个答案:

答案 0 :(得分:1)

  

对于interval_map来说,这个更复杂 - 相互接触且具有不同关联值的间隔将不会被连接:

真的没有区别。

  

我知道如何自定义重叠聚合的过程,但是我需要自定义另一个案例 - 在触摸时聚合。

你似乎暗示

 m += std::make_pair(IMap::interval_type::right_open(4, 8), 2);

将插入[4, 8) -> 2

事实并非如此。它是一个codomain组合操作,结果取决于映射的先前状态。

当然,你可以写下来:

m.set({Ival::right_open(4, 8), 2});

如果需要,您可以查询前面的插槽,因此您的操作可能如下所示:

// returns true if joined with preceding slot
bool fill_slot(IMap& m, int from, int till, int value) {
    bool joined = false;
    auto slot = Ival::right_open(from, till);

    if (within(slot, m)) {
        // There is overlap, I don't know how  you want to handle this.
        // You can add some logic here.
    } else {
        auto preceding = m(from - 1);

        if (preceding && value == preceding + 1) {
            joined = true;
            value = preceding;
        }
    }

    m.set({slot, value});
    return joined;
}

现在您可以编写如下测试用例:

int main() {
    {
        IMap m;
        fill_slot(m,  0,  4,  1);
        fill_slot(m,  4,  8,  2);
        std::cout << m << std::endl;
    }
    {
        IMap m;
        fill_slot(m,  0,  4,  1);
        fill_slot(m,  4,  8,  3);
        std::cout << m << std::endl;
    }
    {
        IMap m;
        fill_slot(m,  0,  4,  1);
        fill_slot(m,  5,  8,  2);
        std::cout << m << std::endl;
    }
}

他们打印 Live On Coliru

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