4

Boost.ICLinterval_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是应该做的吗?我该如何使用它?


编辑 1:这是使用 C++11 的更明确和简化的示例代码

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

namespace icl = boost::icl;
using interval = icl::interval<double>;

int main(){
    icl::interval_map<double, int> joined_map;

    joined_map.insert({interval::open(1., 2.), 1});
    joined_map.insert({interval::open(3., 5.), 2});
    joined_map.insert({interval::open(2.5, 5.), 3}); 
    // ^^^^ this line doesn't replace the old value 2! it keeps it.
    for(auto e: joined_map) std::cout << e.first <<' '<< e.second <<'\n';
    // prints: (1,2) 1 \\ (2.5,3] 3 \\ (3,5) 2
    // desired: (1,2) 1 \\ (2.5,5] 3  // value 2 gone
}

编辑 2: 基于@JorgeBellon 的回答的完整解决方案:

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

namespace icl = boost::icl;

template <class Type>
struct inplace_replace{// : icl::identity_based_inplace_combine<Type>{
    using first_argument_type = Type;
    void operator()(Type& object, Type const& operand) const{object = operand;}
};

using interval = icl::interval<double>;

int main(){

    icl::interval_map<
        double, int,
        icl::partial_enricher,   // Unmapped intervals have unkown value;
                                 // store identity values
        std::less             ,  // Comparator
        inplace_replace     //,  // Combination operator // IMPORTANT!!
    //  icl::inplace_erasure//,  // Extraction operator
    //  closed_interval<unsigned, std::less> // Interval type
    > joined_map;
    joined_map.add({interval::open(1. , 2.), 1}); // or joined_map+=std::make_pair(...)
    joined_map.add({interval::open(3. , 5.), 2}); // IMPORTANT: USE add, NOT insert!!
    joined_map.add({interval::open(2.5, 5.), 3}); 
    // ^^^^ this line now replaces the old value 2
    for(auto e: joined_map) std::cout << e.first <<' '<< e.second <<'\n';
    // prints: (1,2) 1 \\ (2.5,5] 3  // value 2 gone
}
4

2 回答 2

5

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

看它住在 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 映射。

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

  • 没有operator[],但是operator[]超载(返回const
  • find()返回一个const_iterator(大概是因为它可以返回一个以某种方式从实际数据派生的“虚拟节点”)。所以你不能只期望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";
    }
}

See it 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

希望这可以帮助

于 2014-03-24T00:34:01.543 回答
3

区间图的模板参数之一是组合运算符类型。典型示例包括在 map 上使用std::set或类似的值作为值,然后使用加法标识(保留现有值)作为操作。

由于默认情况下不存在覆盖示例,因此您可以创建自己的示例并将其传递给地图:

#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_type_second_argument_typeresult_type
  • 它用于创建该identity_element类型的值(静态函数)。例如,一个集合的标识值是一个空集,对于一个整数它是0(当你求和时很有用)等等。

partial_enricher如果您的地图是或,则不必使用它total_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;
  }
};

注意:较旧的 bo​​ost ICL 实现源自std::binary_function而不是使用这些 typedef。不幸的是,这在 C++11 中已被弃用,并在 C++17 中被删除,所以我会尽量不在你自己的代码中使用它。最新版本实现了类似上面代码片段的函子。

同样的例子:https ://ideone.com/lMLEDw

于 2019-10-28T12:06:04.203 回答