Увеличить карту ICL, которая заменяет значения в интервалах?
ICL Boost 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
должен делать? Как мне это использовать?
1 ответ
Вы можете просто стереть содержимое раздела, который вы собираетесь перезаписать перед вставкой:
Посмотрите это в прямом эфире на 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))
- вы должны явно стереть по ключу или интервалу.- имеются
add
а такжеsubtract
методы (кроме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";
}
}
Посмотреть это в прямом эфире на Колиру, печать:
#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
Надеюсь это поможет
Одним из параметров шаблона карты интервалов является тип оператора комбинации. Типичный пример состоит из карты с использованием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_type
а такжеresult_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;
}
};
Примечание: более старые реализации Boost ICL происходят от std::binary_function
вместо использования этих определений типов. К сожалению, это не рекомендуется в C++11 и удалено в C++17, поэтому я бы попытался не использовать его в вашем собственном коде. В последних версиях реализованы функторы, подобные приведенному выше фрагменту.
Тот же пример: https://ideone.com/lMLEDw