STD :: MAP-如何查找或添加,然后可以在一次搜索中删除项目

std::map - how to lookup or add, then may be delete item in one search

本文关键字:一次 搜索 删除项目 添加 何查找 MAP- 查找 STD 然后      更新时间:2023-10-16

我有这样的地图:

std::map<myDecimal, OrderBookItem> buyContainer;

我需要查找(或添加),修改并可能被删除,类似物品:

OrderBookItem item = buyContainer[price_];
item.lots += lots_;
if (item.lots == 0) {
    buyContainer.erase(price_);
}

,但我认为我正在"搜索"两次。第一次OrderBookItem item = buyContainer[price_];和第二次buyContainer.erase(price_);如何重写我的代码,以便我只搜索一次?可能使用迭代器?

upd

到目前为止,似乎无法在一次搜索中进行所有操作。operator[]允许我查找或添加,但是我必须对删除进行额外的搜索。iterator允许我查找然后擦除,但是我必须进行额外的搜索才能添加项目

使用 find,这将返回一个迭代器,该迭代器将确切的位置保留在地图中,如果将其传递给它,则不会进行第二次搜索。这样的东西:

std::map<myDecimal, OrderBookItem>::iterator it = buyContainer.find(price_);
OrderBookItem item = it->second;
item.lots += lots_;
if (item.lots == 0) {
    buyContainer.erase(it);
}

您也可能想从itemOrderBookItem& item)中进行参考,以便调整地图中的实际值,而不是本地副本。

编辑:如果您还想插入(如其他注释和更新中所述),则可以使用lower_bound而不是find,如本文所述。这样就是这样(未测试):

std::map<myDecimal, OrderBookItem>::iterator it = buyContainer.lower_bound(price_);
if(it != mymap.end() && !(buyContainer.key_comp()(price_, it->first)))
    OrderBookItem item = it->second;
    item.lots += lots_;
    if (item.lots == 0) {
        buyContainer.erase(it);
    }
} else {
    // determine value (variable v below), e.g. OrderBookItem v{};
    buyContainer.insert(it, std::map<myDecimal, OrderBookItem>::value_type(price_, v));
}

这里的优势是,如果项目已经存在,则不会运行与构造v相关的代码。如果这不是真正复杂的代码,也可以使用以下C 11解决方案。优势在于,这也与unordered_map一起使用,并且在不需要时仍然避免了不必要的value_type构造。

auto insertion = buyContainer.insert({price_, {arguments_to_OrderBookItem_constructor}});
if(insertion.second) // Item already existed, remove if you also want op on new item(s)
{
    auto item = insertion.first->second; //Possibly make auto& as stated above
    item.lots += lots_;
    if (item.lots == 0) {
        buyContainer.erase(insertion.first);
    }
}

没有C 11,您还可以简单地构造std::map<myDecimal, OrderBookItem>::value_type对象并提供该对象以插入而不是C 11完美转发。请参阅 @Erbureth的答案。但是,同样,您可以通过原始解决方案完全避免使用该构造,如果您关心插入/删除/查找MAP的性能,这已经很快了。

您想要的是

std::map<myDecimal, OrderBookItem>::iterator it = buyContainer.find(price_);
if(it != buyContainer.end())
{
   OrderBookItem& item = it->second;
   item.lots += lots_;
   if (item.lots == 0) {
     buyContainer.erase(it);
   }
}
else{ // insert if not existing
     OrderBookItem item;
     item.lots += lots_;
     if (item.lots != 0) {
        buyContainer[price_] = item;
     }
}

请注意,您发布的代码中可能存在一个错误,因为您修改了本地对象item

是的,使用iterator

std::map<myDecimal, OrderBookItem> buyContainer;
std::map<myDecimal, OrderBookItem>::iterator item
    = buyContainer.insert(std::makePair(price_, OrderBookItem())).first;
if (satisfiesCond(item->second)) {
    buyContainer.erase(item);
}

iterator类型用作stl容器中元素的指针,因此搜索仅执行一次。

std::map::insert文档:

如果容器尚未包含具有等效键的元素,则将元素(s)插入容器中。

编辑:如果不存在,这也将创建项目。

使用迭代器:

std::map<myDecimal, OrderBookItem>::iterator iter = buyContainer.find(price_);
if (iter->second.lots + lots_ == 0) {
    buyContainer.erase(iter);
}

还要注意,您没有在示例中修改该项目,因为您没有获得参考,而是在值中(因此您将其复制)。使用迭代器,您将获得参考。因此,如果要修改地图中的项目,请执行此操作:

std::map<myDecimal, OrderBookItem>::iterator iter = buyContainer.find(price_);
iter->second.lots += lots_
if (iter->second.lots == 0) {
    buyContainer.erase(iter);
}

您应该使用迭代器擦除。首先找到指向数据的迭代器,然后使用迭代器删除数据。

http://www.cplusplus.com/reference/map/map/map/find/:

// map::find
#include <iostream>
#include <map>
int main ()
{
  std::map<char,int> mymap;
  std::map<char,int>::iterator it;
  mymap['a']=50;
  mymap['b']=100;
  mymap['c']=150;
  mymap['d']=200;
  it=mymap.find('b');
  mymap.erase (it);
  mymap.erase (mymap.find('d'));
  // print content:
  std::cout << "elements in mymap:" << 'n';
  std::cout << "a => " << mymap.find('a')->second << 'n';
  std::cout << "c => " << mymap.find('c')->second << 'n';
  return 0;
} 

如果使用find()搜索地图,则将迭代器返回到位置,然后可以将erase()与迭代器一起使用,例如:

std::map<myDecimal, OrderBookItem> buyContainer;
std::map<myDecimal, OrderBookItem>::iterator it;
it = buyContainer.find(price_); //only searching map once
if(it != buyContainer.end())
{
    if(it->second += lots_ == 0)
    {
        buyContainer.erase(it);
}