带有映射的Lambda函数,其中键是元组,值是double

时间:2018-03-16 13:24:56

标签: c++ c++11 stdtuple

我有一张充满价值的地图:

std::map<std::tuple<int, int, double>, double> Cache;

当地图的大小大于100时,我想删除/删除关键元组中的值都超过10的地图元素。以下是while和{if的处理方法。 {1}}:

if (Cache.size() > 100) {
    auto it = Cache.begin();
    while (it != Cache.end()) {
        auto myCache = it->first;
        auto actualX = std::get<0>(myCache);
        auto actualY = std::get<1>(myCache);
        auto actualZ = std::get<2>(myCache);
        if (abs(actualX) > 10 || abs(actualY) > 10) || abs(actualZ) > 10)) {
            Cache.erase(it++);
        } else {
            it++;
        }
    }
}

如何使用find_if(或其他函数)和lambda函数实现相同的行为?

UPDATE2

在浏览评论部分提供的维基百科链接后,我实现了以下代码,但它给出了编译错误:(

Cache.erase(std::remove_if(Cache.begin(),
                                 Cache.end(),
                                 [=](auto &T) -> bool {
                                     auto myCache = T->first;
                                     auto actualX = std::get<0>(myCache);
                                     auto actualY = std::get<1>(myCache);
                                     return std::abs(actualX) > 10|| std::abs(actualY) > 10 || std::abs(actualZ) > 10;
                                 }),
                  Cache.end());

更新3

以上不能与地图一起使用;(

4 个答案:

答案 0 :(得分:1)

您可以将std::find_if与谓词一起使用:

auto pred = []( const auto &t ) { 
    return std::abs( std::get<0>( t. ) ) > 10 || 
           std::abs( std::get<1>( t ) ) > 10 || 
           std::fabs( std::get<2>( t ) ) > 10.0 ); };

for( auto it = Cache.begin(); true; it = Cache.erase( it ) ) {
     it = std::find_if( it, Cache.end(), pred );
     if( it == Cache.end() ) break;
}

答案 1 :(得分:0)

以下内容应该有效

namespace myUtility {

template< typename C, typename P >
  void custom_erase_if( C& items, const P& predicate ) {
    for( auto it = items.begin(); it != items.end(); ) {
      if( predicate(*it) ) it = items.erase(it);
      else ++it;
    }
  }
}

然后,

  myUtility::custom_erase_if( Cache, [](const auto& x) {
     auto myCache = x.first;
            auto actualX = std::get<0>(myCache);
            auto actualY = std::get<1>(myCache);
            auto actualZ = std::get<2>(myCache);
            return ( std::abs(actualX) > 10 || 
                    std::abs(actualY) > 10  || 
                    std::abs(actualZ) > 10) ) ; 
    } );

答案 2 :(得分:0)

您应该做的是安排地图,以便您想要的元素位于地图的背面。

struct over_10 {
  bool operator()( std::tuple<int, int, double> const& t) const {
    return
      (std::get<0>(t)>10 || std::get<0>(t)<-10) // min int doesn't like abs
   && (std::get<1>(t)>10 || std::get<1>(t)<-10)
   && fabs(std::get<2>(t))>10.0;
  }
};
template<class Split>
struct split_order {
  template<class Lhs, class Rhs>
  bool operator()( Lhs const& lhs, Rhs const& rhs ) const {
    auto split = Split{};
    return std::tie( split(lhs), lhs ) < std::tie( split(rhs), rhs );
  }
};
using split_on_10_order = split_order<over_10>;

它的作用是分割排序,以便通过over_10测试的所有内容都是最后排序的。在每个“分裂”中,一切都是明智的。

现在:

std::map<std::tuple<int, int, double>, double, split_on_10_order> Cache;

auto it = Cache.lower_bound(
  std::make_tuple(
    std::numeric_limits<int>::min(),
    std::numeric_limits<int>::min(),
    std::numeric_limits<double>::min()
  )
);

Cache.erase( it, Cache.end() );

并完成。

这需要大约O(lg n)时间来找到分割,然后O(m)删除应该删除的m个元素。

答案 3 :(得分:0)

不幸的是,正如Slava指出的那样,export class Client { name= ''; familyName = ''; public toString(){ return this.name+ " " + this.familyName; } 无法与地图一起使用。

我认为你的解决方案(擦除不需要的元素的循环)并不坏,但是如果你想使用算法库,那么我最好的就是使用if ENV['USER'].downcase == 'yourusername' config.vm.synced_folder "/media/hdd", "/media/hdd", type: "virtualbox" end 来强>移动要保留在临时地图中的元素,然后交换两张地图。

我的意思是......像

一样
std::remove_if

不幸的是,lambda函数的std::copy_if()参数只能从C ++ 14开始提供,所以如果你需要一个C ++ 11解决方案,而不是 if ( Cache.size() > 100 ) { std::map<std::tuple<int, int, double>, double> CacheTmp; std::copy_if(std::make_move_iterator(Cache.begin()), std::make_move_iterator(Cache.end()), std::inserter(CacheTmp, CacheTmp.end()), [] (auto const & p) { return (std::abs(std::get<0>(p.first)) <= 10) && (std::abs(std::get<1>(p.first)) <= 10) && (std::abs(std::get<2>(p.first)) <= 10.0); }); Cache.swap(CacheTmp); } ,你的lambda应该得到一个{ {1}}