2012-12-27 9 views
8

मैं वर्तमान में इस कोड को सक्रिय करने और चलाने के लिए है:पाशन द्वारा C++ का मेल मानक एल्गोरिदम केवल एक बार

string word="test,"; 
string::iterator it = word.begin(); 
for (; it != word.end(); it++) 
{ 
    if (!isalpha(*it)) { 
     break; 
    } 
    else { 
     *it = toupper(*it); 
    } 
} 
word.erase(it, word.end()); 
// word should now be: TEST 

मैं चाहूँगा यह अधिक कॉम्पैक्ट और पठनीय द्वारा इसे बनाने के लिए:

  1. मौजूदा मानक सी लिखना ++ एल्गोरिदम (*)
  2. केवल एक बार पाश प्रदर्शन करना

(*) मैं यह सोचते हैं रहा है कि ग मौजूदा एल्गोरिदम ombining मेरी कोड अधिक पठनीय बनाता है ...

एक वैकल्पिक समाधान

एक कस्टम transform_until एल्गोरिथ्म को परिभाषित करने, के रूप में ज्रोक ने सुझाव दिया करने के लिए इसके अलावा, यह एक कस्टम इटरेटर एडाप्टर का उपयोग कर पुनरावृति हैं परिभाषित करने के लिए संभव हो सकता है अंतर्निहित पुनरावर्तक लेकिन इसे वापस करने से पहले अंतर्निहित संदर्भ को संशोधित करके ऑपरेटर *() को फिर से परिभाषित करें। कुछ इस तरह:

template <typename Iterator, typename UnaryFunction = typename Iterator::value_type (*)(typename Iterator::value_type)> 
class sidefx_iterator: public std::iterator< 
         typename std::forward_iterator_tag, 
         typename std::iterator_traits<Iterator>::value_type, 
         typename std::iterator_traits<Iterator>::difference_type, 
         typename std::iterator_traits<Iterator>::pointer, 
         typename std::iterator_traits<Iterator>::reference > 
{ 
    public: 
    explicit sidefx_iterator(Iterator x, UnaryFunction fx) : current_(x), fx_(fx) {} 

    typename Iterator::reference operator*() const { *current_ = fx_(*current_); return *current_; } 
    typename Iterator::pointer operator->() const { return current_.operator->(); } 
    Iterator& operator++() { return ++current_; } 
    Iterator& operator++(int) { return current_++; } 
    bool operator==(const sidefx_iterator<Iterator>& other) const { return current_ == other.current_; } 
    bool operator==(const Iterator& other) const { return current_ == other; } 
    bool operator!=(const sidefx_iterator<Iterator>& other) const { return current_ != other.current_; } 
    bool operator!=(const Iterator& other) const { return current_ != other; } 
    operator Iterator() const { return current_; } 

    private: 
    Iterator current_; 
    UnaryFunction fx_; 
}; 

बेशक यह अभी भी बहुत कच्चे है, लेकिन यह पता चलना चाहिए कि। ऊपर अनुकूलक के साथ, मैं उसके बाद निम्न लिख सकते हैं:

word.erase(std::find_if(it, it_end, std::not1(std::ref(::isalpha))), word.end()); 
साथ

अग्रिम में परिभाषित (कुछ टेम्पलेट जादू से सरल किया जा सकता है) के बाद:

using TransformIterator = sidefx_iterator<typename std::string::iterator>; 
TransformIterator it(word.begin(), reinterpret_cast<typename std::string::value_type(*)(typename std::string::value_type)>(static_cast<int(*)(int)>(std::toupper))); 
TransformIterator it_end(word.end(), nullptr); 

तो मानक को शामिल किया जाएगा ऐसा एडाप्टर मैं इसका उपयोग करूंगा, क्योंकि इसका मतलब यह होगा कि यह निर्दोष था, लेकिन चूंकि यह मामला नहीं है, इसलिए शायद मैं अपना लूप रखूंगा।

इस तरह के एक एडाप्टर मौजूदा एल्गोरिदम और उन्हें अलग अलग तरीकों से मिश्रण आज संभव नहीं है पुन: उपयोग करने की अनुमति होगी, लेकिन यह रूप में अच्छी तरह कमियां हो सकता है, जो मैं संभावना पल में अनदेखी कर रहा हूँ ...

+0

मेरे वर्तमान कोड में एक लूप है। मेरा मुद्दा यह था कि पुनर्लेखन के बाद भी एक लूप होगा। –

+1

'isalpha (* it) 'पर आधारित समयपूर्व पलायन एकमात्र चीज है जो मैं आपको जो कुछ भी ढूंढ रहा हूं उसे प्राप्त करने से संभावित रूप से आपको रोक रहा हूं, और ईमानदारी से, जो कुछ भी आपके लिए कर सकता है (और मैं नहीं कर सकता तत्काल कुछ भी देखें जो संभवतः) इतनी गड़बड़ हो जाएगी कि आप स्पष्टता-कारक खिड़की से बाहर निकल जाएंगे। मैं आपके पास जो कुछ भी रखता हूं उसके साथ रहूंगा। – WhozCraig

+0

आपके प्रेरणादायक उत्तरों के लिए सभी को धन्यवाद। मैं अभी के लिए अपने वर्तमान कोड के साथ रहना होगा। मेरा मानना ​​है कि 'boost :: transform_iterator' निकटतम चीज़ है जिसे मैं ढूंढ रहा था। इस उपयोग के मामले को "साइड इफेक्ट्स" इटरेटर एडाप्टर द्वारा कवर किया जाएगा, इस तरह इस्तेमाल किया जाने वाला कुछ: 'word.erase (std :: find_if (sidefx_iterator (word.begin(), :: toupper), word.end (), std :: not1 (:: isalpha)), word.end()); ' –

उत्तर

9

मुझे नहीं लगता कि एक मानक एल्गोरिदम के साथ ऐसा करने का एक साफ तरीका है।मुझे पता नहीं है कि कोई भी भविष्यवाणी नहीं करता है (आपको यह तय करने की आवश्यकता है कि जल्दी कब ब्रेक करना है) और स्रोत अनुक्रम के तत्वों को संशोधित करने की अनुमति देता है।

यदि आप वास्तव में इसे "मानक" तरीका करना चाहते हैं तो आप अपना खुद का सामान्य एल्गोरिदम लिख सकते हैं। इसे कहते हैं, हम्म, transform_until करते हैं:

#include <cctype> 
#include <string> 
#include <iostream> 

template<typename InputIt, typename OutputIt, 
     typename UnaryPredicate, typename UnaryOperation> 
OutputIt transform_until(InputIt first, InputIt last, OutputIt out, 
         UnaryPredicate p, UnaryOperation op) 
{ 
    while (first != last && !p(*first)) { 
     *out = op(*first); 
     ++first; 
     ++out; 
    } 
    return first; 
} 

int main() 
{ 
    std::string word = "test,"; 
    auto it = 
    transform_until(word.begin(), word.end(), word.begin(), 
        [](char c) { return !::isalpha(static_cast<unsigned char>(c)); }, 
        [](char c) { return ::toupper(static_cast<unsigned char>(c)); }); 
    word.erase(it, word.end()); 
    std::cout << word << '.'; 
} 

यह है कि क्या यह किसी भी तुम्हारे पास क्या है :) कभी कभी पाश के लिए एक सादे सबसे अच्छा है की तुलना में बेहतर है यह बहस का मुद्दा है।

+5

+1, यह उतना अच्छा है जितना मुझे लगता है कि ओपी प्राप्त करने जा रहा है। हालांकि उसे योजना ए के साथ रहना चाहिए और बस अपना लूप रखना चाहिए, यह जवाब एक कस्टम कंटेनर ट्रांसफॉर्मर लिखने का एक बहुत अच्छा अवधारणा है, उचित नाम है, और अभी भी ओपी के सवाल का जवाब देता है। भले ही ओपी इसका उपयोग न करे, फिर भी एक अच्छा जवाब। – WhozCraig

+0

मैंने इस उत्तर को स्वीकार कर लिया है क्योंकि परिणामी कोड छोटा और पठनीय है, और सामान्य एल्गोरिदम व्यक्त करता है जो सामान्य रूप से उपयोगी होगा। सभी मौजूदा एसटीएल एल्गोरिदम में एक निश्चित अंत इटरेटर होता है और पूरे कंटेनर में लूप की आवश्यकता होती है। मुझे लगता है कि यह एक सशर्त अंत करने में सक्षम होने की एक सामान्य आवश्यकता है। –

0

बेहतर समझ के बाद आपका प्रश्न, मुझे एक ऐसा विचार है जो काम कर सकता है, लेकिन Boost की आवश्यकता है।

आप इस्तेमाल कर सकते हैं एक transform_iterator जो सभी पात्रों पर toupper कॉल करता है और उपयोग करने वाले find_if या remove_if को inputiterator के रूप में। हालांकि, उदाहरण के लिए बूस्ट के साथ पर्याप्त परिचित नहीं हूं।

जैसा कि @jrok बताता है, ट्रांसफॉर्म_इटरेटर केवल पुनरावृत्ति के दौरान मूल्य को बदल देगा और वास्तव में मूल कंटेनर को संशोधित नहीं करेगा। इसके आस-पास पहुंचने के लिए, उसी अनुक्रम पर परिचालन करने के बजाय, आप remove_copy_if जैसे कुछ का उपयोग करके एक नए प्रतिलिपि बनाना चाहते हैं। जब तक भविष्यवाणी सत्य नहीं है तब तक यह प्रतियां, इसलिए std::not1 की आवश्यकता होगी। यह remove_if मामले को प्रतिस्थापित करेगा।

std::copy का उपयोग करें जब तक कि अन्य मामले को काम करने के लिए std::find_if द्वारा पुनरावर्तक वापस लौटाया जाए।

अंत में, यदि आपकी आउटपुट स्ट्रिंग खाली है, तो इसे आउटपुट के लिए std::inserter इटरेटर की आवश्यकता होगी।

+0

यह दो बार लूपिंग है - ओपी इससे बचना चाहता था। – jrok

+0

ऐसा लगता है कि आपके कार्यान्वयन में दो लूप हैं ... क्या मैं गलत हूं? –

+0

@ MariJosé आह मैं अब आपके प्रश्न को बेहतर समझता हूं, हाँ आप सही हैं, 2 लूप हैं। –

संबंधित मुद्दे