Most efficient way of erasing/deleting multiple std::vector elements while retaining original order?

前端 未结 7 1406
隐瞒了意图╮
隐瞒了意图╮ 2020-12-23 17:37


i have a std::vector and a second container holding iterators or indexes (no keys, i want constant access to the element) to this vector for del

相关标签:
7条回答
  • 2020-12-23 18:36

    If you have a (e.g. unordered) set of indices that you want to erase, you can use this:

    template <typename Type>
    void erase_indices(
            const std::unordered_set<size_t>& indices_to_erase,
            std::vector<Type>& vec) {
        std::vector<bool> erase_index(vec.size(), false);
        for (const size_t i: indices_to_erase) {
            erase_index[i] = true;
        }
        std::vector<bool>::const_iterator it_to_erase = erase_index.cbegin();
        typename std::vector<Type>::iterator it_erase_from = std::remove_if(
            vec.begin(), vec.end(),
            [&it_to_erase](const Type&) -> bool {
              return *it_to_erase++ == true;
            }
        );
        vec.erase(it_erase_from, vec.end());
    }
    

    It is the fastest solution that came to my mind. You need C++11, though. Usage example to erase elements at index 2 and 5:

    constexpr size_t num = 10u;
    std::vector<int> vec(num);
    std::iota(vec.begin(), vec.end(), 0);
    
    std::unordered_set<size_t> indices_to_erase;
    indices_to_erase.insert(2u);
    indices_to_erase.insert(5u);
    
    erase_indices(indices_to_erase, vec);
    

    Before:

    0 1 2 3 4 5 6 7 8 9
    

    After:

    0 1 3 4 6 7 8 9
    

    Edit: If want to be more flexible regarding type of container that hold the indices to erase:

    template <typename Type, typename Container>
    void erase_indices(
            const Container& indices_to_erase,
            std::vector<Type>& vec) {
        typedef typename Container::value_type IndexType;
        static_assert(std::is_same<IndexType, std::size_t>::value,
            "Indices to be erased have to be of type std::size_t");
        std::vector<bool> erase_index(vec.size(), false);
        for (const IndexType idx_erase: indices_to_erase) {
            erase_index[idx_erase] = true;
        }
        std::vector<bool>::const_iterator it_to_erase = erase_index.cbegin();
        typename std::vector<Type>::iterator it_erase_from = std::remove_if(
            vec.begin(), vec.end(),
            [&it_to_erase](const Type&) -> bool {
              return *it_to_erase++ == true;
            }
        );
        vec.erase(it_erase_from, vec.end());
    }
    

    Now you can use any kind of container from the Containers Library to provide the indices to be erased as long as the value_type of that container is std::size_t. Usage remains the same.

    0 讨论(0)
提交回复
热议问题