C++移除序列中連續(xù)重復(fù)的特定值示例代碼
前言
最近在寫(xiě) YTL 中的字符串相關(guān)輔助函數(shù)。實(shí)現(xiàn)到 split 函數(shù)時(shí),希望能夠?qū)崿F(xiàn)類(lèi)似 Python 當(dāng)中的 str.split 方法的功能。
If sep is not specified or is None , a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace.
—— https://docs.python.org/3/library/stdtypes.html#str.split
也就是說(shuō),在最基本的 split 的基礎(chǔ)上,要添加兩個(gè)功能:
•刪除輸入字符串首尾的空白;
•將字符串中的連續(xù)分隔符當(dāng)成一個(gè)分隔符看待。
前一個(gè)功能很好實(shí)現(xiàn)。將空白符保存在 const char* trim_chars = " \t\n\r\v\f" 當(dāng)中,然后使用 std::string::find_first_not_of 以及 std::string::find_last_not_of 即可找到有效內(nèi)容的起止位置,最后再 std::string::erase 一下就好了。
后一個(gè)功能也不復(fù)雜。但要寫(xiě)得優(yōu)雅——最好是能利用上標(biāo)準(zhǔn)庫(kù)的設(shè)施——就不那么容易了。
std::unique 的基本用法
std::unique 是定義在 algorithm 頭文件內(nèi)的容器算法。它有兩種基本形式:
template< class ForwardIt > ForwardIt unique( ForwardIt first, ForwardIt last ); template< class ForwardIt, class BinaryPredicate > ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p );
其中,第一種形式是第二種形式的特例,它等價(jià)于 BinaryPredicate p 為連續(xù)兩元素相等性判斷時(shí)的第二種形式:
template< class ForwardIt, class BinaryPredicate = std::function<bool(const typename std::iterator_traits<ForwardIt>::value_type&, const typename std::iterator_traits<ForwardIt>::value_type&)> ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p = [](const typename std::iterator_traits<ForwardIt>::value_type& lhs, const typename std::iterator_traits<ForwardIt>::value_type& rhs) { return lhs == rhs; });
這也就是說(shuō),第一種形式的 std::unique 會(huì)找到每個(gè)連續(xù)重復(fù)的區(qū)間,而后保留這些區(qū)間的首個(gè)元素,最后返回新序列邏輯上的尾后迭代器。例如, aabbccaa 經(jīng)過(guò) std::unique 處理之后得到:
abca????
↑
這里用箭頭標(biāo)出的位置,即是 std::unique 的返回值所指向的位置。需要注意的是,經(jīng)過(guò) std::unique 處理之后,容器的實(shí)際大小沒(méi)有發(fā)生改變,甚至邏輯尾后迭代器到容器實(shí)際尾后迭代器之間的左閉右開(kāi)區(qū)間內(nèi)的迭代器仍然是可解引用的(dereferenceable)。但這部分區(qū)間內(nèi)的元素的值是不確定的。因此,在使用 std::unqiue 之后,往往會(huì)調(diào)用容器的 erase 函數(shù)成員,刪除邏輯尾后迭代器開(kāi)始的所有元素。例如:
// #include <string> // #include <algorithm> std::string source("aabbccaa"); source.erase(std::unique(source.begin(), source.end()), source.end()); std::cout << source << std::endl; // expect result: abca
只對(duì)特定內(nèi)容進(jìn)行 std::unique 操作
回到最開(kāi)始的問(wèn)題。我們需要的功能,是針對(duì)分隔符 sep 進(jìn)行操作,將連續(xù)出現(xiàn)的 sep 壓縮成一個(gè)。 std::unique 的默認(rèn)行為則不然,它會(huì)將所有連續(xù)出現(xiàn)的元素都?jí)嚎s成一個(gè)——不光是 sep 。為此,我們需要實(shí)現(xiàn)自己的 BinaryPredicate 。首先,由于我們要指定具體需要被 std::unique 壓縮的元素,我們必然要將其作為函數(shù)參數(shù)傳入函數(shù)。于是我們有以下實(shí)現(xiàn):
// #include <functional> template <typename T> bool AreConsecutiveElements(const T& target, const T& lhs, const T& rhs) { return (lhs == rhs) and (lhs == target); }
std::unique 要求一個(gè)二元謂詞( BinaryPredicate ),但此處我們實(shí)現(xiàn)的是三元謂詞。于是,好在 target 總是應(yīng)當(dāng)預(yù)先給出的,所以我們可以利用 std::bind 將 target 綁定在 AreConsecutiveElements 的第一個(gè)參數(shù)上,產(chǎn)生一個(gè)二元謂詞。
// #include <functional> // using namespace std::placeholders; // #include <string> // #include <algorithm> const char target = 'b' auto binp = std::bind(AreConsecutiveElements, target, _1, _2); std::string source("aabbccaa"); source.erase(std::unique(source.begin(), source.end(), binp), source.end()); std::cout << source << std::endl; // expect result: aabccaa
這里,我們將 'b' 作為壓縮目標(biāo),并將其與 AreConsecutiveElements 綁定在一起,產(chǎn)生一個(gè)新的二元謂詞。最終輸出期待的結(jié)果。
附: std::unique 的一個(gè)可能實(shí)現(xiàn)
template<class ForwardIt, class BinaryPredicate> ForwardIt unique(ForwardIt first, ForwardIt last, BinaryPredicate p) { if (first == last) { return last; } ForwardIt result = first; while (++first != last) { if (!p(*result, *first) && ++result != first) { *result = std::move(*first); } } return ++result; }
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
基于內(nèi)核線程的創(chuàng)建、使用和退出以及延時(shí)宏的補(bǔ)充說(shuō)明介紹
本篇文章是對(duì)內(nèi)核線程的創(chuàng)建、使用和退出以及延時(shí)宏的補(bǔ)充說(shuō)明介紹進(jìn)行了敘述。需要的朋友參考下2013-05-05C語(yǔ)言實(shí)現(xiàn)隨機(jī)搶紅包功能
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)隨機(jī)搶紅包功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) link 鏈表反轉(zhuǎn)的實(shí)現(xiàn)
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) link 鏈表反轉(zhuǎn)的實(shí)現(xiàn)的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下2017-09-09C生萬(wàn)物C語(yǔ)言宏將整數(shù)二進(jìn)制位的奇偶數(shù)位交換
這篇文章主要為大家介紹了C生萬(wàn)物C語(yǔ)言使用宏將整數(shù)二進(jìn)制位的奇偶數(shù)位交換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Visual Studio 2019配置qt開(kāi)發(fā)環(huán)境的搭建過(guò)程
這篇文章主要介紹了Visual Studio 2019配置qt開(kāi)發(fā)環(huán)境的搭建過(guò)程,本文圖文并茂給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03