বিপরীত পুনরুক্তি দিয়ে কীভাবে মুছা কল করবেন


181

আমি এরকম কিছু করার চেষ্টা করছি:

for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
    if ( *i == pCursor )
    {
        m_CursorStack.erase( i );
        break;
    }
}

তবে মুছতে বিপরীত পুনরুক্তিকারী না হয়ে একটি পুনরুক্তি লাগে। কোনও বিপরীত পুনরাবৃত্তিকে নিয়মিত পুনরাবৃত্তিতে রূপান্তর করার কোনও উপায় আছে বা এই উপাদানটি তালিকা থেকে সরানোর অন্য কোনও উপায় আছে?


17
একটি সরু হিসাবে, এগুলির মতো লুপগুলি লেখার সময়, বার বার শেষ পুনরাবৃত্তিটি আপনি এখানে যেমন করেন তেমন গণনা করবেন না i != m_CursorStack.rend()। পরিবর্তে, লিখুন i = m_CursorStack.rbegin(), end = m_CursorStack.rend(); i != end;। এটি, পুনরাবৃত্ত তুলনার জন্য আপনি প্রায় রাখতে পারেন এমন একটি পুনরুদ্ধারকারীকে সূচনা করুন - ধরে নিবেন যে আপনার অবস্থানের লুপটির কোনও পার্শ্ব প্রতিক্রিয়া হিসাবে শেষের অবস্থানটি পরিবর্তন হবে না।
সেখ

আমার কাছে মনে হচ্ছে যে এখানে স্পষ্ট প্রশ্ন হ'ল আপনি কেন এগুলি করছেন। বিপরীতে তালিকাটি অতিক্রম করে আপনি কী অর্জন করবেন? আপনি এই কোডটি ব্যবহার না করে নিজে লিখে লিখে কী অর্জন করবেন std::remove?
জেরি কফিন

এবং একটি এসটিডি :: তালিকার একটি পুনরাবৃত্তির উপাদানটি মোছার পরেও যে উপাদানটি বোঝায় তার পরে বাড়ার ক্ষেত্রে বৈধ?
স্টিভ জেসোপ

3
আমি কেবলমাত্র 1 টি উপাদান মুছতে চাই, সুতরাং 'বিরতি;', 'অপসারণ' ব্যবহার করে যে ম্যাচটি বেশি সময় নেয় এবং আমি যা চাই তা না করে মুক্তি পেতে পারে। এই বিশেষ ক্ষেত্রে আমি যে উপাদানটি মুছতে চাইছি তা প্রায় সর্বদা তালিকার শেষ হতে পারে বা এর খুব কাছাকাছি থাকে, সুতরাং বিপরীতে পুনরাবৃত্তি করাও সমস্যাটির জন্য দ্রুত এবং আরও উপযুক্ত।
0xC0DEFACE

4
stackoverflow.com/a/2160581/12386 এটি বলেছে যে ডিজাইনারগণ বিশেষত প্রয়োগটি সংজ্ঞায়িত করেন না কারণ আপনার ব্যবহারকারী হিসাবে জানা বা যত্ন নেওয়ার কথা নয়, তবুও @ সে উপরের প্রত্যাশা করে যে আমাদের যাদুকরীভাবে কেবল রেন্ড () গণনা করা হবে তা জানতে পারবেন এবং ব্যয়বহুল।
স্টু

উত্তর:


181

আরও কিছু গবেষণা এবং পরীক্ষার পরে আমি সমাধানটি পেয়েছি। আপাতদৃষ্টিতে স্ট্যান্ডার্ড অনুসারে [24.4.1 / 1] i.base () এবং i এর মধ্যে সম্পর্ক:

&*(reverse_iterator(i)) == &*(i - 1)

(একটি ডবস নিবন্ধ থেকে ):

বিকল্প পাঠ

সুতরাং বেস () পাওয়ার সময় আপনাকে একটি অফসেট প্রয়োগ করতে হবে। সুতরাং সমাধানটি হ'ল:

m_CursorStack.erase( --(i.base()) );

সম্পাদনা

সি ++ 11 এর জন্য আপডেট করা হচ্ছে।

রিভার্স_িট্রেটর iঅপরিবর্তিত:

m_CursorStack.erase( std::next(i).base() );

রিভার্স_িটরেটর iউন্নত:

std::advance(i, 1);
m_CursorStack.erase( i.base() );

আমি আমার আগের সমাধানের তুলনায় এটিকে আরও স্পষ্ট মনে করি। আপনার যা প্রয়োজন ব্যবহার করুন।


27
আপনি যে নিবন্ধটি উদ্ধৃত করেছেন তার আরও কিছুটা লক্ষ্য করা উচিত - বহনযোগ্য হওয়ার জন্য ভাবটি হওয়া উচিত m_CursorStack.erase( (++i).base())(মানুষ, বিপরীত পুনরুক্তি দিয়ে এই জিনিসটি করা আমার মাথাকে আঘাত দেয় ...)। এটিও লক্ষ করা উচিত যে ডিডিজে নিবন্ধটি মায়ারের "কার্যকর এসটিএল" বইয়ের সাথে সংযুক্ত করা হয়েছে।
মাইকেল বুড় 6

8
আমি এই চিত্রটি সাহায্যকারী চেয়ে আরও বিভ্রান্ত মনে করি। যেহেতু রবেগিন, রি এবং রেন্ড সবগুলিই মূলত উপাদানটির দিকে ইশারা করছে যা তারা নির্দেশ করছে of ডায়াগ্রামটি দেখায় যে আপনি যদি *তাদের মধ্যে কোন উপাদানটি অ্যাক্সেস করতে পারবেন তবে আমরা যদি আপনি সেগুলি কীসের দিকে ইঙ্গিত করতেন সে সম্পর্কে কথা বলছি baseযা ডানদিকে একটি উপাদান। আমি এমন অনুরাগী নই --(i.base())বা (++i).base()সমাধান যেহেতু তারা পুনরুক্তিকারীর পরিবর্তন ঘটান। আমি পছন্দ করি (i+1).base()যা কাজ করে।
mgiuca

4
বিপরীত পুনরাবৃত্তি মিথ্যাবাদী .. যখন সম্মানিত হয়, একটি বিপরীত পুনরাবৃত্তি তার আগে উপাদানটি ফেরত দেয় । এখানে দেখুন
bobobobo

4
কেবল একেবারে পরিষ্কার করার জন্য, এই কৌশলটি এখনও লুপের জন্য সাধারণভাবে ব্যবহার করা যায় না (যেখানে সাধারণ পদ্ধতিতে পুনরুক্তি বৃদ্ধি করা হয়)। দেখুন stackoverflow.com/questions/37005449/...
logidelic

1
m_CursorStack.erase ((++ i) .base ()) দেখে মনে হচ্ছে এটি যদি সমস্যা হয় তবে যদি ++ আমি আপনাকে শেষ উপাদানটি অতীত করে ফেলেছি। আপনি কি মুছে ফেলা শেষ করতে পারেন ()?
স্টু

16

দয়া করে নোট করুন যে m_CursorStack.erase( (++i).base())কোনও forলুপে ব্যবহৃত হলে সমস্যা হতে পারে (মূল প্রশ্নটি দেখুন) কারণ এটি i এর মান পরিবর্তন করে। সঠিক অভিব্যক্তি হয়m_CursorStack.erase((i+1).base())


4
আপনাকে iterator j = i ; ++ji+1
পুনরাবৃত্তকারীটির

3
@ বোবোবো, আপনি m_CursorStack.erase(boost::next(i).base())বুস্ট দিয়ে ব্যবহার করতে পারেন । বা সি ++ 11m_CursorStack.erase(std::next(i).base())
এএফসি

12

... অথবা এই উপাদানটি তালিকা থেকে সরানোর অন্য কোনও উপায়?

এর জন্য -std=c++11পতাকাটির প্রয়োজন (এর জন্য auto):

auto it=vt.end();
while (it>vt.begin())
{
    it--;
    if (*it == pCursor) //{ delete *it;
        it = vt.erase(it); //}
}

একটি কবজ কাজ করে :)
ডেন-জেসন

@ গেটানোমেনডোলা: কেন?
স্ল্যাশমেজ

3
কে আপনাকে গ্যারান্টি দেয় যে একটি তালিকার পুনরাবৃত্তি আদেশ করা হয়েছে?
গায়েতানো মেন্ডোলা

7

মজার বিষয় এই পৃষ্ঠায় এখনও কোন সঠিক সমাধান নেই। সুতরাং, নিম্নলিখিতটি সঠিক:

ফরোয়ার্ড ইটারেটরের ক্ষেত্রে সমাধানটি সরাসরি এগিয়ে থাকে:

std::list< int >::iterator i = myList.begin();
while ( ; i != myList.end(); ) {
  if ( *i == to_delete ) {
    i = myList.erase( i );
  } else {
    ++i;
  } 
}

বিপরীত পুনরাবৃত্তির ক্ষেত্রে আপনার একই কাজ করা দরকার:

std::list< int >::reverse_iterator i = myList.rbegin();
while ( ; i != myList.rend(); ) {
  if ( *i == to_delete ) {
    i = decltype(i)(myList.erase( std::next(i).base() ));
  } else {
    ++i;
  } 
}

মন্তব্য:

  • আপনি একটি নির্মাণ করতে পারেন reverse_iterator একটি পুনরুক্তিকারী থেকে একটি
  • আপনি এর রিটার্ন মান ব্যবহার করতে পারেন std::list::erase

এই কোডটি কাজ করে, তবে দয়া করে ব্যাখ্যা করুন যে এর পরে কেন ব্যবহৃত হয় এবং কীভাবে কোনও ফরোয়ার্ড ইটারেটরকে পৃথিবী ভেঙে না ফেলে কোনও বিপরীত পুনরুক্তি করতে দেওয়া নিরাপদ
লেফটারিস ই

1
পছন্দ করুন এটি একটি ইন্টারেক্টরের বাইরে একটি নতুন বিপরীত পুনরাবৃত্তি তৈরি করে। এটি বিপরীত পুনরুদ্ধারকের সাধারণ নির্মাণকারী।
আইমন তৃত

3

reverse_iteratorএর base()পদ্ধতিটি ব্যবহার এবং ফলাফল হ্রাস করার সময় এখানে কাজ করে, এটি লক্ষ্য করার মতো যে reverse_iteratorনিয়মিত iteratorগুলি হিসাবে একই মর্যাদা দেওয়া হয় না । সাধারণভাবে, আপনার যেমন নিয়মিত কারণের জন্য নিয়মিত iteratorগুলি reverse_iteratorএর (পাশাপাশি const_iteratorএস এবং const_reverse_iteratorএস) পছন্দ করা উচিত। কেন এর গভীরতর আলোচনার জন্য ডক্টর ডবস জার্নালটি দেখুন ।


3
typedef std::map<size_t, some_class*> TMap;
TMap Map;
.......

for( TMap::const_reverse_iterator It = Map.rbegin(), end = Map.rend(); It != end; It++ )
{
    TMap::const_iterator Obsolete = It.base();   // conversion into const_iterator
    It++;
    Map.erase( Obsolete );
    It--;
}

3

এবং বিপরীতে পুনরাবৃত্ত হওয়ার সময় একটি ধারকটিতে কোনও উপাদান মুছতে মুছার ফলাফলটিকে বিপরীত পুনরায় পুনরায় রূপান্তর করতে কোডের টুকরোটি এখানে দেওয়া হয়েছে। কিছুটা অদ্ভুত, তবে এটি প্রথম বা শেষ উপাদানটি মুছার পরেও কাজ করে:

std::set<int> set{1,2,3,4,5};

for (auto itr = set.rbegin(); itr != set.rend(); )
{    
    if (*itr == 3)
    {
        auto it = set.erase(--itr.base());
        itr = std::reverse_iterator(it);            
    }
    else
        ++itr;
}

2

আপনার পাশাপাশি চলার সাথে সাথে যদি সবকিছু মুছে ফেলার দরকার না হয়, তবে সমস্যাটি সমাধান করার জন্য, আপনি মুছে ফেলুন-মুছা আইডিয়ামটি ব্যবহার করতে পারেন:

m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());

std::removeকনটেইনারটিতে থাকা সমস্ত আইটেম অদলবদল pCursorকরে যা শেষের সাথে মিলে যায় এবং প্রথম ম্যাচের আইটেমটিতে একটি পুনরাবৃত্তিকে ফেরত দেয়। তারপরে, eraseব্যাপ্তিটি ব্যবহার করে প্রথম ম্যাচটি মুছে যাবে এবং শেষ পর্যন্ত যাবে। মেলে না এমন উপাদানগুলির ক্রম সংরক্ষণ করা হয়েছে।

আপনি যদি এমন কোনও ব্যবহার করছেন std::vector, যেখানে সামগ্রীর মাঝখানে মুছে ফেলা অনেকগুলি অনুলিপি বা চলন্তের সাথে জড়িত থাকতে পারে তবে এটি আপনার জন্য দ্রুত কাজ করতে পারে।

অথবা অবশ্যই, উপরের উত্তরগুলি ব্যবহারের ব্যাখ্যা ব্যাখ্যা করার reverse_iterator::base()জন্য আকর্ষণীয় এবং জ্ঞানযোগ্য, সঠিক সমস্যাটি বর্ণিত সমাধান করার জন্য, আমি যুক্তি দিই যে std::removeএটি আরও উপযুক্ত।


1

কেবল কিছু স্পষ্ট করতে চেয়েছিলেন: উপরের কয়েকটি মন্তব্য এবং উত্তরে মুছার জন্য বহনযোগ্য সংস্করণটি (++ i) .বেস () হিসাবে উল্লেখ করা হয়েছে। তবে যতক্ষণ না আমি কিছু হারিয়ে ফেলছি সঠিক বিবৃতিটি হ'ল (++ রি) .বেস (), যার অর্থ আপনি 'ইনক্রিমেন্ট' রিভার্স_াইটেটর (পুনরাবৃত্তকারী নয়)।

আমি গতকাল অনুরূপ কিছু করার প্রয়োজনে ছুটলাম এবং এই পোস্টটি সহায়ক ছিল। ধন্যবাদ সবাইকে.


0

অন্যের উত্তরগুলির পরিপূরক করতে এবং যেহেতু আমি খুব বেশি সাফল্য ছাড়াই এইচটিডি :: স্ট্রিংয়ের সন্ধান করার সময় এই প্রশ্নটিতে হোঁচট খেয়েছি, এখানে স্ট্যান্ড :: স্ট্রিং, স্টাডি :: স্ট্রিং :: মুছা এবং স্ট্যান্ড :: রিভার্স_াইটেটর ব্যবহারের সাথে একটি প্রতিক্রিয়া চলেছে

আমার সমস্যাটি একটি সম্পূর্ণ ফাইল নাম স্ট্রিং থেকে একটি চিত্র ফাইলের নাম মুছছিল। এটি মূলত std :: স্ট্রিং :: সন্ধান_লাইস্ট_এর সাহায্যে সমাধান করা হয়েছিল, তবুও আমি std :: revers_iterator এর সাথে বিকল্প পদ্ধতি নিয়ে গবেষণা করি।

std::string haystack("\\\\UNC\\complete\\file\\path.exe");
auto&& it = std::find_if( std::rbegin(haystack), std::rend(haystack), []( char ch){ return ch == '\\'; } );
auto&& it2 = std::string::iterator( std::begin( haystack ) + std::distance(it, std::rend(haystack)) );
haystack.erase(it2, std::end(haystack));
std::cout << haystack;  ////// prints: '\\UNC\complete\file\'

এটি অ্যালগরিদম, পুনরুক্তি এবং স্ট্রিং শিরোনাম ব্যবহার করে।


0

বিপরীত পুনরুদ্ধারকারী ব্যবহার করা বেশ শক্ত। সুতরাং সবেমাত্র সাধারণ পুনরায় ব্যবহৃত। 'আর' এটি শেষ উপাদান থেকে শুরু হয়। মুছে ফেলার জন্য যখন কিছু খুঁজে পান। এটি মুছুন এবং পরবর্তী পুনরুক্তি ফিরে আসুন। উদাহরণস্বরূপ, যখন তৃতীয় উপাদান মোছা এটি বর্তমান চতুর্থ উপাদানটি নির্দেশ করবে। এবং নতুন 3 য়। সুতরাং বাম দিকে সরানোর জন্য এটি 1 হ্রাস করা উচিত

void remchar(string& s,char c)
{      
    auto r = s.end() - 1;
    while (r >= s.begin() && *r == c)
    {
        r = s.erase(r);
        r -= 1;
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.