পুনরুক্তি করার সময় কোনও মানচিত্র থেকে কীভাবে সরানো যায়?


177

আমি কোনও মানচিত্রটিকে পুনরাবৃত্তি করার সময় কীভাবে সরিয়ে ফেলব? মত:

std::map<K, V> map;
for(auto i : map)
    if(needs_removing(i))
        // remove it from the map

আমি যদি map.eraseএটি ব্যবহার করি তবে এটি পুনরাবৃত্তিকারীদের অবৈধ করে দেবে





উত্তর:


280

স্ট্যান্ডার্ড এসোসিয়েটিভ-কন্টেইনার মুছা প্রতিমা:

for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
  if (must_delete)
  {
    m.erase(it++);    // or "it = m.erase(it)" since C++11
  }
  else
  {
    ++it;
  }
}

নোট করুন যে আমরা সত্যিই forএখানে একটি সাধারণ লুপ চাই , যেহেতু আমরা নিজেই ধারকটি পরিবর্তন করছি। পরিসীমা ভিত্তিক লুপটি এমন পরিস্থিতিতে কঠোরভাবে সংরক্ষণ করা উচিত যেখানে আমরা কেবলমাত্র উপাদানগুলির যত্ন করি। আরবিএফএল এর বাক্য গঠনটি লুপের দেহের অভ্যন্তরে থাকা ধারকটি প্রকাশ না করে এটি পরিষ্কার করে দেয়।

সম্পাদনা করুন। প্রাক-সি ++ 11, আপনি কনস্ট-ইটারেটরগুলি মুছতে পারেননি। সেখানে আপনাকে বলতে হবে:

for (std::map<K,V>::iterator it = m.begin(); it != m.end(); ) { /* ... */ }

ধারক থেকে উপাদান মুছে ফেলা উপাদানটির স্থিরতার সাথে মতবিরোধ নয়। উপমা অনুসারে, এটি সর্বদা পুরোপুরি বৈধ ছিল delete pযেখানে pপয়েন্টার-থেকে-ধ্রুবক। দৃ Const়তা আজীবন বাধা দেয় না; সি ++ এ থাকা কনট মানগুলি এখনও বিদ্যমান থাকা বন্ধ করতে পারে।


1
"লুপের দেহের অভ্যন্তরে পাত্রেও উন্মোচন করা হচ্ছে না" আপনার অর্থ কী?
দানি

2
@ দানি: ঠিক আছে, এটি বিংশ শতাব্দীর নির্মাণের সাথে বিপরীতে for (int i = 0; i < v.size(); i++)। এখানে আমাদের v[i]লুপের ভিতরে বলতে হবে, অর্থাৎ আমাদের অবশ্যই স্পষ্টভাবে ধারকটির উল্লেখ করতে হবে। অন্যদিকে আরবিএফএল লুপ ভেরিয়েবলের পরিচয় দেয় যা মান হিসাবে সরাসরি ব্যবহারযোগ্য এবং লুপের ভিতরে ধারকটির কোনও জ্ঞানের প্রয়োজন নেই। এটি লুপগুলির জন্য যেগুলি ধারক সম্পর্কে জানতে হবে না তার জন্য আরবিএফএল ব্যবহারের উদ্দেশ্যে একটি সূত্র । মুছে ফেলা সম্পূর্ণ বিপরীত পরিস্থিতি, যেখানে এটি সমস্ত ধারক সম্পর্কে।
কেরেক এসবি

3
@ স্কাইহিসি: আসলেই। এটি পোস্ট-ইনক্রিমেন্টের বৈধ ব্যবহারগুলির মধ্যে একটি: পরবর্তী, বৈধ পুনরাবৃত্তকারী পেতে প্রথমে বর্ধিতকরণ itএবং তারপরে পুরানোটি মুছতে। এটি অন্যভাবে কাজ করে না!
কেরেক এসবি

5
আমি কোথাও পড়েছি যে সি ++ 11 এ it = v.erase(it);এখন মানচিত্রের জন্যও কাজ করে hat এটি হল সমস্ত মিশ্র উপাদানগুলিতে মুছুন () এখন পরবর্তী পুনরাবৃত্তিকে ফেরত দেয়। সুতরাং মুছে ফেলা () এর মধ্যে পোস্ট-ইনক্রিমেন্ট ++ প্রয়োজন এমন পুরানো কুলডেজের আর প্রয়োজন নেই। এই (যদি সত্য হয়) একটি ভাল জিনিস, কারণ ক্লাডেজ ওভাররাইড-পোস্ট-ইনক্রিমেন্ট-এ-ফাংশন-কল-যাদুতে নির্ভর করে, নবাগত রক্ষণাবেক্ষণকারীদের দ্বারা ফাংশন কলটি থেকে ইনক্রিমেন্টটি সরিয়ে নিতে বা এটি অদলবদল করতে "কারণ এটি কেবল একটি স্টাইলের জিনিস" ইত্যাদির প্রতি
দেবী মরগান

3
কেন তুমি কল করবে it++মধ্যে if এবং else ব্লক? এর পরে কি একবার ফোন করা যথেষ্ট হবে না ?
nburk

25

আমি অতিরিক্ত এই ভেরিয়েবলের ব্যয়ে ব্যক্তিগতভাবে এই প্যাটার্নটি পছন্দ করি যা কিছুটা পরিষ্কার এবং সহজ:

for (auto it = m.cbegin(), next_it = it; it != m.cend(); it = next_it)
{
  ++next_it;
  if (must_delete)
  {
    m.erase(it);
  }
}

এই পদ্ধতির সুবিধা:

  • লুপ ইনক্রিমেন্টর একটি ইনক্রিমেন্টর হিসাবে উপলব্ধি করে;
  • মুছে ফেলা অপারেশনটি একটি সাধারণ মুছা, বর্ধিত যুক্তির সাথে মিশ্রিত না হয়ে;
  • লুপ বডিটির প্রথম লাইনের পরে, পুনরাবৃত্তির সর্বত্র অর্থ itএবং next_itএটি স্থির থাকে, যাতে তারা সহজেই তাদের উদ্দেশ্য হিসাবে অতিরিক্ত কাজ করতে পারে কিনা তা লক্ষ্য করে অতিরিক্ত বিবৃতি যুক্ত করতে দেয় (অবশ্যই এটি itমুছে যাওয়ার পরে আপনি ব্যবহার করতে পারবেন না ) ।

2
আমি আসলে আরও একটি সুবিধা নিয়ে ভাবতে পারি, যদি লুপটি কোডে কল করে যা এন্ট্রিটি পূর্বে বা পূর্ববর্তীগুলিতে পুনরাবৃত্তি হচ্ছে (এবং লুপটি এটি অজানা) এটি কোনও ক্ষতি না করেই কাজ করবে। কেবলমাত্র সীমাবদ্ধতা হ'ল নেক্সট_আইটি বা উত্তরসূরীদের দ্বারা নির্দেশিত কিছু মুছে ফেলা হচ্ছে কিনা। একটি সম্পূর্ণ সাফ তালিকা / মানচিত্র পাশাপাশি পরীক্ষা করা যেতে পারে।
লারসওয়াদ

এই উত্তরটি সহজ এবং স্পষ্ট, এমনকি লুপটি আরও জটিল এবং মুছে ফেলা বা না করা বা অন্যান্য বিভিন্ন কাজগুলি করার সিদ্ধান্ত নেওয়ার জন্য একাধিক স্তরের যুক্তি রয়েছে। আমি এটিকে কিছুটা সহজ করার জন্য একটি সম্পাদনার প্রস্তাব করেছি। টাইপস এড়ানোর জন্য ফরেক্সের আরআইটিতে "পরের_এটি" "এটি" এ সেট করা যেতে পারে এবং যেহেতু আরআইআর এবং পুনরাবৃত্তি বিবৃতি উভয়ই সেট করে এবং পরের_একটি একই মানগুলিতে সেট করে, আপনাকে "Next_it = it" বলার দরকার নেই; লুপের শুরুতে।
সিডগ্রাহাম

1
এই উত্তরটি যে কেউ ব্যবহার করে তা মনে রাখবেন: আপনার অবশ্যই লুপের জন্য "++ Next_it" থাকতে হবে, এবং পুনরাবৃত্তির বহিঃপ্রকাশে নয়। আপনি যদি এটির পুনরুক্তিটি "it = next_it ++" হিসাবে স্থানান্তরিত করার চেষ্টা করেন, তবে শেষ পুনরাবৃত্তির পরে, যখন "এটি" "m.cend ()" এর সমান সেট হতে চলেছে, আপনি "Next_it" পুনরাবৃত্তি করার চেষ্টা করবেন অতীত "m.cend ()", যা ভুল।
সিডগ্রাহাম

6

সংক্ষেপে "আমি কোনও মানচিত্রের পুনরাবৃত্তি করার সময় এটি থেকে কীভাবে সরিয়ে ফেলব?"

  • পুরানো মানচিত্রের প্ররোচনা সহ: আপনি পারবেন না
  • নতুন মানচিত্রের ইমপ্লের সাথে: প্রায় @ কেরেকএসবি প্রস্তাবিত। তবে তিনি যা পোস্ট করেছেন তাতে কিছু সিনট্যাক্স সমস্যা রয়েছে।

জিসিসি মানচিত্র ইমপ্ল থেকে (নোট GXX_EXPERIMENTAL_CXX0X ):

#ifdef __GXX_EXPERIMENTAL_CXX0X__
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // DR 130. Associative erase should return an iterator.
      /**
       *  @brief Erases an element from a %map.
       *  @param  position  An iterator pointing to the element to be erased.
       *  @return An iterator pointing to the element immediately following
       *          @a position prior to the element being erased. If no such 
       *          element exists, end() is returned.
       *
       *  This function erases an element, pointed to by the given
       *  iterator, from a %map.  Note that this function only erases
       *  the element, and that if the element is itself a pointer,
       *  the pointed-to memory is not touched in any way.  Managing
       *  the pointer is the user's responsibility.
       */
      iterator
      erase(iterator __position)
      { return _M_t.erase(__position); }
#else
      /**
       *  @brief Erases an element from a %map.
       *  @param  position  An iterator pointing to the element to be erased.
       *
       *  This function erases an element, pointed to by the given
       *  iterator, from a %map.  Note that this function only erases
       *  the element, and that if the element is itself a pointer,
       *  the pointed-to memory is not touched in any way.  Managing
       *  the pointer is the user's responsibility.
       */
      void
      erase(iterator __position)
      { _M_t.erase(__position); }
#endif

পুরানো এবং নতুন শৈলীর সাথে উদাহরণ:

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>

using namespace std;
typedef map<int, int> t_myMap;
typedef vector<t_myMap::key_type>  t_myVec;

int main() {

    cout << "main() ENTRY" << endl;

    t_myMap mi;
    mi.insert(t_myMap::value_type(1,1));
    mi.insert(t_myMap::value_type(2,1));
    mi.insert(t_myMap::value_type(3,1));
    mi.insert(t_myMap::value_type(4,1));
    mi.insert(t_myMap::value_type(5,1));
    mi.insert(t_myMap::value_type(6,1));

    cout << "Init" << endl;
    for(t_myMap::const_iterator i = mi.begin(); i != mi.end(); i++)
        cout << '\t' << i->first << '-' << i->second << endl;

    t_myVec markedForDeath;

    for (t_myMap::const_iterator it = mi.begin(); it != mi.end() ; it++)
        if (it->first > 2 && it->first < 5)
            markedForDeath.push_back(it->first);

    for(size_t i = 0; i < markedForDeath.size(); i++)
        // old erase, returns void...
        mi.erase(markedForDeath[i]);

    cout << "after old style erase of 3 & 4.." << endl;
    for(t_myMap::const_iterator i = mi.begin(); i != mi.end(); i++)
        cout << '\t' << i->first << '-' << i->second << endl;

    for (auto it = mi.begin(); it != mi.end(); ) {
        if (it->first == 5)
            // new erase() that returns iter..
            it = mi.erase(it);
        else
            ++it;
    }

    cout << "after new style erase of 5" << endl;
    // new cend/cbegin and lambda..
    for_each(mi.cbegin(), mi.cend(), [](t_myMap::const_reference it){cout << '\t' << it.first << '-' << it.second << endl;});

    return 0;
}

কপি করে প্রিন্ট:

main() ENTRY
Init
        1-1
        2-1
        3-1
        4-1
        5-1
        6-1
after old style erase of 3 & 4..
        1-1
        2-1
        5-1
        6-1
after new style erase of 5
        1-1
        2-1
        6-1

Process returned 0 (0x0)   execution time : 0.021 s
Press any key to continue.

1
আমি পাই না। সমস্যাটা কী mi.erase(it++);?
lvela

1
@ ল্যাভেলা অপ্ট দেখুন। "আমি যদি মানচিত্র ব্যবহার করি se তবে এটি পুনরাবৃত্তিকারীদের অবৈধ করে দেবে"।
কাশ্যপ

মোছার পরে, মানচিত্রটি খালি হয়ে গেলে আপনার নতুন পদ্ধতিটি কাজ করবে না। সেক্ষেত্রে পুনরুক্তিকারীকে অবৈধ করা হবে। সুতরাং, মুছার পরে শীঘ্রই, sertোকানো ভাল if(mi.empty()) break;
রাহাত জামান

4

সি ++ 20 খসড়াটিতে সুবিধাদির কাজ রয়েছে std::erase_if

সুতরাং আপনি সেই ফাংশনটি ওয়ান-লাইনার হিসাবে এটি করতে ব্যবহার করতে পারেন।

std::map<K, V> map_obj;
//calls needs_removing for each element and erases it, if true was reuturned
std::erase_if(map_obj,needs_removing);
//if you need to pass only part of the key/value pair
std::erase_if(map_obj,[](auto& kv){return needs_removing(kv.first);});

3

খুব দুঃখ, আহ? আমি সাধারণত যেভাবে এটি করি তা হ'ল ট্র্যাভারসাল চলাকালীন মোছার পরিবর্তে পুনরাবৃত্তকারীদের একটি ধারক তৈরি করা। তারপরে ধারকটি লুপ করুন এবং মানচিত্র ব্যবহার করুন era

std::map<K,V> map;
std::list< std::map<K,V>::iterator > iteratorList;

for(auto i : map ){
    if ( needs_removing(i)){
        iteratorList.push_back(i);
    }
}
for(auto i : iteratorList){
    map.erase(*i)
}

তবে একটি মুছে ফেলার পরে বাকীটি অবৈধ হবে
দানি


@ দানি: মানচিত্রে নেই। মানচিত্রে মুছে ফেলা কেবল মুছে ফেলা আইটেমটিতে পুনরাবৃত্তিকারীকে অবৈধ করে।
আঙ্কেলবেন্স

3

সি ++ 11 ধরে নিলে, এটি যদি আপনার প্রোগ্রামিং শৈলীর সাথে সামঞ্জস্য হয় তবে এখানে একটি ওয়ান-লাইনার লুপ বডি রয়েছে:

using Map = std::map<K,V>;
Map map;

// Erase members that satisfy needs_removing(itr)
for (Map::const_iterator itr = map.cbegin() ; itr != map.cend() ; )
  itr = needs_removing(itr) ? map.erase(itr) : std::next(itr);

অন্যান্য কিছু ছোট ছোট স্টাইলের পরিবর্তন:

  • Map::const_iteratorসম্ভাব্য / সুবিধাজনক হলে ব্যবহারের পরে ঘোষিত প্রকার ( ) প্রদর্শন করুন auto
  • usingটেমপ্লেট প্রকারের জন্য ব্যবহার করুন , আনুষঙ্গিক প্রকারগুলি ( Map::const_iterator) পড়া / বজায় রাখা সহজ easier
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.