Delete all not found, i.e. delete all keys / values ​​on the map not found in the set

I tried, but could not do the following with std::algorithms: I have a std::map<key_t,value_t> cacheand std::set<key_t> selected_items, and I want to remove the key / value pairs from cache, with the exception of the keys contained in selected_items.

Here is what I wrote without algorithms:

//This could really be written better with std::algorithms but time...
//Delete old
for (auto pair = cache.begin(); pair != cache.end(); ) {
    if (selected_items.find(pair->first) == selected_items.end())
        pair = cache.erase(pair);
    else
        ++pair;
}

To use the library of algorithms, I decided what I need to use std::set_differencewith the comparison function and std::removeor std::map::erase. But I can not connect the pieces, failed:

  • What is the correct comparison function?
  • Should I generate a temporary set with the keys that need to be deleted, or can I use the output iterator directly to delete / delete?

What should my code look like?

+4
4

! , ...

  • std::map std::pair<const Key, T>, / std::pairs ( const)
  • std::map<>::erase(),
  • cache (, std::partition), cache - 1

:

  • , erase
  • <algorithm> ,

, , . std::set_difference(), , .
, std::map std::set (std::pair Key), Comparator.
- , const std::pair & a const Key &. ! ( , ... Mac OS X 10.10.5), std::set_difference() Comparator ...

, SFINAE std::set_difference():

#include <map>
#include <set>
#include <iterator>
#include <algorithm>

using Key = int;
using Value = char;

using Pair = std::map<Key,Value>::value_type;

struct Comparator
{
    // Maybe use a custom comparator instead of '<' (see std::set documentation)
    template<class P, class K> auto operator()( const P &p, const K &k ) -> decltype(p.first < k)
    { return (p.first < k); }
    template<class P, class K> auto operator()( const K &k, const P &p ) -> decltype(k < p.first)
    { return (k < p.first); }
};

int main( void )
{
    std::map<Key,Value> cache = { {1, 'a'}, {2, 'b'}, {3, 'c'}, {4, 'd'} };
    std::set<Key> selected_items = { 2, 4 };

    std::map<Key,Value> new_cache;
    std::set_difference( cache.begin(), cache.end(),
                        selected_items.begin(), selected_items.end(),
                        std::inserter( new_cache, new_cache.end() ),
                        Comparator() );
    cache = std::move( new_cache ); // Don't use new_cache from here on

    return 0;
}
+5

key_t, , , . O (N).

, , . .

+1

:

#include <iostream>
#include <map>
#include <set>

int main() {
    std::map<int, int> m = {{1, 2}, {3, 4}, {4, 5}};
    std::set<int> s = {1, 3, 5};
    for (auto it = begin(m); it != end(m); ){
        if (s.count(it->first))
            m.erase(it++);
        else
            ++it;
    }
    for (auto &e : m){
        std::cout << e.first << ' ' << e.second << '\n';
    }
}

@MaximEgorushkin:

#include <iostream>
#include <map>
#include <set>

void erase_elements_from_map_that_are_not_in_set(
    std::map<int, int> &m, std::set<int> &s){   
    auto sit = begin(s);
    for (auto it = begin(m); it != end(m) && sit != end(s); ){
        while (*sit < it->first){
            ++sit;
            if (sit == end(s))
                return;
        }
        if (*sit == it->first)
            m.erase(it++);
        else
            ++it;
    }
}
int main() {
    std::map<int, int> m = {{1, 2}, {3, 4}, {4, 5}};
    std::set<int> s = {1, 3, 5};
    erase_elements_from_map_that_are_not_in_set(m, s);
    for (auto &e : m){
        std::cout << e.first << ' ' << e.second << '\n';
    }
}

, < while s m.

STL, std::find count , . STL , , . erase_elements_from_map_that_are_not_in_set, .

+1
source

This is similar to the erase-delete idiom case :

typedef std::map<int,std::string> cache_t;
typedef std::set<cache_t::key_type> set_t;

void update_cache(cache_t& cache, const set_t& selected_items)
{
    auto test = [selected_items](const cache_t::value_type& x){
        return selected_items.find(x.first) == selected_items.end();
    };
    cache.erase(std::remove_if(cache.begin(), cache.end(), test), cache.end());
}

But this is not possible here because the error message indicates:

32883794.cc:16:64:   required from here
/usr/include/c++/4.8/bits/stl_pair.h:170:8: error: assignment of read-only member ‘std::pair<const int, std::basic_string<char> >::first’
  first = std::forward<first_type>(__p.first);

The problem is that we get only iteratorof pair<const int key_t, value_t>from map, so we cannot move its elements.

It should be possible to use std::copy_ifto create a new instance cache, but it will likely have significant memory overhead compared to the loop approach.

+1
source

Source: https://habr.com/ru/post/1609763/


All Articles