std :: map에 해당하는 remove_if
특정 조건을 기반으로지도에서 다양한 요소를 지우려고했습니다. STL 알고리즘을 사용하여 어떻게합니까?
처음에는 사용 remove_if
하려고 생각 했지만 관련 컨테이너에서 remove_if가 작동하지 않으므로 불가능합니다.
map에 작동하는 "remove_if"동등한 알고리즘이 있습니까?
간단한 옵션으로 맵을 반복하고 지우는 것을 생각했습니다. 그러나지도를 반복하고 안전한 옵션을 지우고 있습니까? (반복자가 지운 후 무효화되므로)
다음 예제를 사용했습니다.
bool predicate(const std::pair<int,std::string>& x)
{
return x.first > 2;
}
int main(void)
{
std::map<int, std::string> aMap;
aMap[2] = "two";
aMap[3] = "three";
aMap[4] = "four";
aMap[5] = "five";
aMap[6] = "six";
// does not work, an error
// std::remove_if(aMap.begin(), aMap.end(), predicate);
std::map<int, std::string>::iterator iter = aMap.begin();
std::map<int, std::string>::iterator endIter = aMap.end();
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
return 0;
}
거의.
for(; iter != endIter; ) {
if (Some Condition) {
aMap.erase(iter++);
} else {
++iter;
}
}
요소를 지우면 원래 반복자가 두 번 증가 합니다. 지워야 할 요소를 건너 뛸 수 있습니다.
이것은 여러 곳에서 사용되고 문서화 된 일반적인 알고리즘입니다.
[편집] 지우기 후에 반복자가 무효화되는 것이 맞지만, 삭제 된 요소를 참조하는 반복자 만 다른 반복자는 여전히 유효합니다. 따라서 통화에 사용 iter++
합니다 erase()
.
std :: map 및 다른 컨테이너의 경우 erase_if
나는 이것을 위해 다음 템플릿을 사용합니다.
namespace stuff {
template< typename ContainerT, typename PredicateT >
void erase_if( ContainerT& items, const PredicateT& predicate ) {
for( auto it = items.begin(); it != items.end(); ) {
if( predicate(*it) ) it = items.erase(it);
else ++it;
}
}
}
아무 것도 반환하지 않지만 std :: map에서 항목을 제거합니다.
사용 예 :
// 'container' could be a std::map
// 'item_type' is what you might store in your container
using stuff::erase_if;
erase_if(container, []( item_type& item ) {
return /* insert appropriate test */;
});
두 번째 예 (테스트 값을 전달할 수 있음) :
// 'test_value' is value that you might inject into your predicate.
// 'property' is just used to provide a stand-in test
using stuff::erase_if;
int test_value = 4; // or use whatever appropriate type and value
erase_if(container, [&test_value]( item_type& item ) {
return item.property < test_value; // or whatever appropriate test
});
훌륭한 SGI STL 참조 에서이 문서를 얻었습니다 .
맵에는 새 요소를 맵에 삽입해도 기존 요소를 가리키는 반복자가 무효화되지 않는다는 중요한 특성이 있습니다. 맵에서 요소를 지워도 실제로 지워지는 요소를 가리키는 반복자에 대한 반복자를 제외하고는 반복자가 무효화되지 않습니다.
So, the iterator you have which is pointing at the element to be erased will of course be invalidated. Do something like this:
if (some condition)
{
iterator here=iter++;
aMap.erase(here)
}
The original code has only one issue:
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
Here the iter
is incremented once in the for loop and another time in erase, which will probably end up in some infinite loop.
Now, std::experimental::erase_if
is available in header <experimental/map>
.
See: http://en.cppreference.com/w/cpp/experimental/map/erase_if
From the bottom notes of:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
a Pair Associative Container cannot provide mutable iterators (as defined in the Trivial Iterator requirements), because the value type of a mutable iterator must be Assignable, and pair is not Assignable. However, a Pair Associative Container can provide iterators that are not completely constant: iterators such that the expression (*i).second = d is valid.
First
Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.
Second, the following code is good
for(; iter != endIter; )
{
if(Some Condition)
{
aMap.erase(iter++);
}
else
{
++iter;
}
}
When calling a function, the parameters are evaluated before the call to that function.
So when iter++ is evaluated before the call to erase, the ++ operator of the iterator will return the current item and will point to the next item after the call.
IMHO there is no remove_if()
equivalent.
You can't reorder a map.
So remove_if()
can not put your pairs of interest at the end on which you can call erase()
.
Based on Iron Savior's answer For those that would like to provide a range more along the lines of std functional taking iterators.
template< typename ContainerT, class FwdIt, class Pr >
void erase_if(ContainerT& items, FwdIt it, FwdIt Last, Pr Pred) {
for (; it != Last; ) {
if (Pred(*it)) it = items.erase(it);
else ++it;
}
}
Curious if there is some way to lose the ContainerT
items and get that from the iterator.
Steve Folly's answer I feel the more efficient.
Here is another easy-but-less efficient solution:
The solution uses remove_copy_if
to copy the values we want into a new container, then swaps the contents of the original container with those of the new one:
std::map<int, std::string> aMap;
...
//Temporary map to hold the unremoved elements
std::map<int, std::string> aTempMap;
//copy unremoved values from aMap to aTempMap
std::remove_copy_if(aMap.begin(), aMap.end(),
inserter(aTempMap, aTempMap.end()),
predicate);
//Swap the contents of aMap and aTempMap
aMap.swap(aTempMap);
If you want to erase all elements with key greater than 2, then the best way is
map.erase(map.upper_bound(2), map.end());
Works only for ranges though, not for any predicate.
I use like this
std::map<int, std::string> users;
for(auto it = users.begin(); it <= users.end()) {
if(<condition>){
it = users.erase(it);
} else {
++it;
}
}
참고URL : https://stackoverflow.com/questions/800955/remove-if-equivalent-for-stdmap
'IT story' 카테고리의 다른 글
Javadoc을 사용하여 @um 값에 연결하는 방법 (0) | 2020.08.02 |
---|---|
수동 배포와 Amazon Elastic Beanstalk (0) | 2020.08.02 |
가져 오기없이 gpg 키 세부 사항을 표시하는 방법은 무엇입니까? (0) | 2020.08.02 |
IIS 오류 502.5의 ASP.NET Core 1.0 (0) | 2020.07.30 |
Maven으로 간단한 Java 10 / Java 11 프로젝트를 컴파일 할 수 없습니다 (0) | 2020.07.30 |