提升ICL地图替换间隔中的值?

时间:2014-03-23 17:52:13

标签: c++ boost boost-icl

Boost.ICL' interval_map有两种行为:+=insert。 两者在不同的背景下都很有用。 第一个将两个现有区间的共同交叉点中的值相加。 第二个只是在以前未分配的区间中引入新值(在先前分配的区间中保留值)。

但是,我需要一种略有不同的行为,以便在下面的示例中,而不是获取不需要的间隔映射(1.,2.)->1 , (2.5,3.)->3, (3.,5.)->2,而是获得所需的(1.,2.)->1 , (2.5,5.)->3

也就是说,新插入的值会替换旧值吗? 如何声明interval_map以获取替换行为?

#include<boost/icl/interval_map.hpp>
int main(){
    boost::icl::interval_map<double, int> joined_map;
    joined_map.insert( std::make_pair(
        boost::icl::interval<double>::open(1., 2.),
        1
    ));
    joined_map.insert( std::make_pair(
        boost::icl::interval<double>::open(3., 5.),
        2
    ));
    joined_map.insert( std::make_pair(
        boost::icl::interval<double>::open(2.5, 5.),
        3
    )); // this line doesn't replace the old value 2, it keeps it.
}

奖金:那是boost::icl::map应该做的吗?我该如何使用它?

2 个答案:

答案 0 :(得分:4)

您可以在插入之前简单地删除您想要覆盖的部分的内容:

查看 Live On Coliru

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

namespace icl = boost::icl;

int main()
{
    icl::interval_map<double, int> joined_map;
    using ival = icl::interval<double>;

    joined_map.add({ival::open(1., 2.), 1});
    joined_map.add({ival::open(3., 5.), 2});
    std::cout << "#1: "; for(auto el : joined_map) std::cout << el.first << ": " << el.second << ", "; std::cout << "\n";

    joined_map.erase(ival::open(3., 6.));
    joined_map.add({ival::open(3., 6.), 4});
    std::cout << "#2: "; for(auto el : joined_map) std::cout << el.first << ": " << el.second << ", "; std::cout << "\n";
}

打印:

#1: (1,2): 1, (3,5): 2, 
#2: (1,2): 1, (3,6): 4, 

我认为这就是你想要的。


漫画救济未来参考

的旧答案文本

我感觉interval_map语义不是你所期望的。我现在已经玩了一点,并且不能说我理解它,但我知道足够明白那里不是简单的1:1映射插入的东西和&#39;元素&#39;存储在容器中。

出于这个原因,std :: map出现了许多令人惊讶的偏差

  • 没有operator[],但operator[]已超载(返回const
  • find()会返回const_iterator(大概是因为它可以返回虚拟节点&#39;它以某种方式从实际数据中获得)。所以你不能指望map.erase(find(k)) - 你必须按键或间隔明确地擦除。
  • addsubtract方法(insert除外)。

演示代码:

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

namespace icl = boost::icl;

int main()
{
    icl::interval_map<double, int,
       icl::partial_absorber,
       /*ICL_COMPARE Compare =*/ ICL_COMPARE_INSTANCE(ICL_COMPARE_DEFAULT, double), 
       /*ICL_COMBINE Combine =*/ ICL_COMBINE_INSTANCE(icl::inplace_plus, int), 
       /*ICL_SECTION Section =*/ ICL_SECTION_INSTANCE(icl::inter_section, int)
        > joined_map;
    using ival = icl::interval<double>;

    joined_map.add({ival::open(1., 2.), 1});
    joined_map.add({ival::open(3., 5.), 2});
    std::cout << "#1: "; for (auto el : joined_map) std::cout << el.first << ": " << el.second << ", "; std::cout << "\n";
    auto clone1 = joined_map;

    joined_map.add({3., 2});
    std::cout << "#2: "; for (auto el : joined_map) std::cout << el.first << ": " << el.second << ", "; std::cout << "\n";
    auto clone2 = joined_map;

    joined_map.add({3., 2});
    std::cout << "#3: "; for (auto el : joined_map) std::cout << el.first << ": " << el.second << ", "; std::cout << "\n";
    auto clone3 = joined_map;

    joined_map.add({ival::open(0., 6.), 10});
    std::cout << "#4: "; for (auto el : joined_map) std::cout << el.first << ": " << el.second << ", "; std::cout << "\n";
    auto clone4 = joined_map;

    for (double x = 0; x < 7; x += .5)
    {
        std::cout << x
            << "\t" << clone1(x)
            << "\t" << clone2(x)
            << "\t" << clone3(x)
            << "\t" << clone4(x) 
            << "\n";
    }
}

查看 Live On Coliru ,打印:

#1: (1,2): 1, (3,5): 2, 
#2: (1,2): 1, [3,5): 2, 
#3: (1,2): 1, [3,3]: 4, (3,5): 2, 
#4: (0,1]: 10, (1,2): 11, [2,3): 10, [3,3]: 14, (3,5): 12, [5,6): 10, 
0   0   0   0   0
0.5 0   0   0   10
1   0   0   0   10
1.5 1   1   1   11
2   0   0   0   10
2.5 0   0   0   10
3   0   2   4   14
3.5 2   2   2   12
4   2   2   2   12
4.5 2   2   2   12
5   0   0   0   10
5.5 0   0   0   10
6   0   0   0   0
6.5 0   0   0   0

希望这有帮助

答案 1 :(得分:2)

间隔图的模板参数之一是组合运算符类型。 典型示例包含使用std::set或类似值作为值的map,然后将加成 identity (保留现有值)用作操作。 / p>

由于默认情况下没有 overwrite 示例,因此您可以创建自己的示例并将其传递给地图:

#include <boost/icl/interval_map.hpp>

using namespace boost::icl;

// interval_map combiner functor: assigns new value if key exists
template <class Type>
struct inplace_replace : identity_based_inplace_combine<Type> {
  void operator()(Type &object, const Type &operand) const {
    object = operand;
  }
};

template<>
inline std::string unary_template_to_string<inplace_replace>::apply() {
  return "=";
}

// When adding, if interval exists, replaces value.
// When subtracting, if interval exists, removes value.
using ival_map =
    interval_map<unsigned,         // Key
                 unsigned,         // Value
                 partial_enricher, // Unmapped intervals have unkown value; store identity values
                 std::less,        // Comparator
                 inplace_replace,  // Combination operator
                 inplace_erasure,  // Extraction operator
                 >;

查看完整的示例:https://ideone.com/C49bDM

编辑:从identity_based_inplace_combine<Type>boost/icl/functors.hpp)派生以下内容:

  • 定义first_argument_typesecond_argument_typeresult_type
  • 它用于为该类型(静态函数)创建identity_element值。例如,一个集合的标识值是一个空集合,整数​​则为0(在求和时很有用),等等。

如果您的地图是partial_enrichertotal_enricher,则不一定要使用它,因为在这种情况下,地图将包含任何值的条目,包括身份值。对于absorber类型,您将需要它,因为在这种情况下,地图需要知道是否可以删除间隔。

替代方法:

// interval_map combiner functor: assigns new value if key exists
template <class Type>
struct inplace_replace {
  typedef void result_type;
  typedef Type& first_argument_type;
  typedef const Type& second_argument_type;

  void operator()(Type &object, const Type &operand) const {
    object = operand;
  }
};

注意:较早的boost ICL实现是从std::binary_function派生的,而不是使用这些typedef。不幸的是,这在C ++ 11中已弃用,而在C ++ 17中已删除,因此我将尽量不要在自己的代码中使用它。最新版本实现了像上面的代码片段这样的函子。

同一示例:https://ideone.com/lMLEDw