Увеличить карту 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

Другие вопросы по тегам