19 Temmuz 2019 Cuma

Erase Remove Idiom

Giriş
Not : Yeni C++ ile bu idiom yerine std::erase() veya std::erase_if() kullanılması önerilir. Böylece bir şey daha tarih oluyor.

Nasıl Kullanılır
Bu idiom container'ın kendi erase() metodu artı std::remove veya std::remove_if ile kullanılır.

Hangi Container İle Kullanılır
- Bu idiom  std::vector, std::deque ve std::std::basic_string için kullanılır.
- std::forward_list ve std::list kendi remove_if() metodularını sağlarlar.
- std::set, std::map, std::multiset, std::multimap, std::unordered_set, std::unordered_map, std::unordered_multiset, std::unordered_multimap için kendi erase() metodları kullanılabilir.

std::remove metodu
Şöyle yaparız.
v.erase(std::remove(v.begin(), v.end(), myvalue), vec.end());
std::remove_if metodu
En çok bu yöntem kullanılıyor. Açıklaması şöyle. Silinmeyecek yani muhafaza edilecek elemanlar baş tarafa kopyalanır.
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. 
Görsel olarak şöyle. Çift sayılar muhafaza edileceği için dolaştıkça "write position" iteratorünün gösterdiği yere kopyalanır.
v               - read position
   1 2 3 4 8 5     - X will denotes shifted from value = unspecified
   ^               - write position
     v          
   1 2 3 4 8 5     1 is odd, ++read
   ^
       v
   2 X 3 4 8 5     2 is even, *write=move(*read), ++both
     ^   
         v
   2 X 3 4 8 5     3 is odd, ++read
     ^
           v
   2 4 3 X 8 5     4 is even, *write=move(*read), ++both
       ^
             v
   2 4 8 X X 5     8 is even, *write=move(*read), ++both
         ^

   2 4 8 X X 5     5 is odd, ++read
         ^         - this points to the new end.
Örnek
Predicate bir lambda olabilir. Öncede predicate tanımlarız.
auto predicate = [](const vec3 &v) { return v.z < 0; }
Şöyle yaparız.
v.erase(std::remove_if(v.begin(), v.end(), predicate), v.end());
Örnek
Şöyle yaparız.
container.erase(
    std::remove_if(
        container.begin(), container.end(),
        [](const auto& element) ->bool { return /* condition */; }),
    vec.end());
Örnek
Şöyle yaparız.
v.erase(std::remove_if(v.begin(), v.end(), [](auto item) { ... }), v.end());
Örnek
Şu kod hatalı.
c.erase(std::remove_if(c.begin(), c.end(), pred));
//                                             , c.end() //---> missing here
Şu kod hatalı.
c.erase((std::remove_if(c.begin(), c.end(), pred), c.end()))
//      ^^                                               ^^
// extra () makes it pass only c.end() to the c.erase

Hiç yorum yok:

Yorum Gönder