std :: মানচিত্রের জন্য সমাপ্তি_ফল


118

আমি নির্দিষ্ট শর্তের ভিত্তিতে মানচিত্র থেকে বিভিন্ন উপাদান মুছে ফেলার চেষ্টা করছিলাম। আমি কীভাবে এটি এসটিএল অ্যালগরিদম ব্যবহার করে করব?

প্রাথমিকভাবে আমি ব্যবহারের কথা ভেবেছিলাম remove_ifতবে এটি সম্ভব নয় কারণ সরানো_আইএফ সংঘবদ্ধ পাত্রে কাজ করে না।

মানচিত্রের জন্য কাজ করে এমন কোনও "মুছে ফেলা_ আইফ" আছে কি?

একটি সহজ বিকল্প হিসাবে, আমি মানচিত্রের লুপিং এবং মুছে ফেলার কথা ভাবি। তবে কী মানচিত্রটি লুপিং করে কোনও নিরাপদ বিকল্পটি মুছে ফেলা হচ্ছে? (পুনরাবৃত্তি মোছার পরে অবৈধ হয়ে উঠেছে)

আমি নিম্নলিখিত উদাহরণ ব্যবহার করেছি:

bool predicate(const std::pair<int,std::string>& x)
{
    return x.first > 2;
}

int main(void) 
{

    std::map<int, std::string> aMap;

    aMap[2] = "two";
    aMap[3] = "three";
    aMap[4] = "four";
    aMap[5] = "five";
    aMap[6] = "six";

//      does not work, an error
//  std::remove_if(aMap.begin(), aMap.end(), predicate);

    std::map<int, std::string>::iterator iter = aMap.begin();
    std::map<int, std::string>::iterator endIter = aMap.end();

    for(; iter != endIter; ++iter)
    {
            if(Some Condition)
            {
                            // is it safe ?
                aMap.erase(iter++);
            }
    }

    return 0;
}

আপনি কী বোঝান যে সরানো_আইফ কাজ করে না?
dirkgently

আমি মানচিত্রে কোনও উপাদান খুঁজে পেতে মুছে ফেলা_ইফ ব্যবহার করতে পারি না, তাই না? এটি একটি সংকলন সময় ত্রুটি দিয়েছে। আমি কিছু অনুপস্থিত করছি?
এজে।

নাহ - এটি মুছে ফেলা হিসাবে কাজ করে না যেমন ক্রমটি পুনরায় অর্ডার করে কাজ করে এমন উপাদানগুলি সরিয়ে দেয় যা শর্তটিকে শেষের দিকে ফেলে দেয়। অতএব এটি একটি টি [এন] তে কাজ করে তবে কোনও মানচিত্র <টি, ইউ> নয়।
এমসাল্টারস

2
সি + 11 দিয়ে আপনি for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....}বিশৃঙ্খলা কমাতে ব্যবহার করতে পারেন । অন্যরা যেমন বলেছিল তেমন বিশ্রাম। এই প্রশ্নটি আমাকে এখনই কিছু চুল বিভাজন থেকে বাঁচিয়েছে ;-)
অতুল কুমার

উত্তর:


111

প্রায়।

for(; iter != endIter; ) {
     if (Some Condition) {
          iter = aMap.erase(iter);
     } else {
          ++iter;
     }
}

আপনি মূলত পুনরুক্তিকারীর বাড়ায় হবে করেছিলেন কি দুইবার যদি আপনি এটি থেকে একটি উপাদান নিশ্চিহ্ন হয়নি; আপনি মুছে ফেলা দরকার যে উপাদানগুলি সম্ভাব্যভাবে এড়িয়ে যেতে পারে।

এটি একটি সাধারণ অ্যালগরিদম যা আমি বহু জায়গায় ব্যবহার এবং নথিভুক্ত দেখেছি।

[সম্পাদনা] আপনি সঠিক যে পুনরাবৃত্তকারীরা মুছে ফেলার পরে অবৈধ হয়, তবে কেবল পুনরাবৃত্তিকারীরা মুছে ফেলা উপাদানটির উল্লেখ করে, অন্যান্য পুনরাবৃত্তিগুলি এখনও বৈধ। অত: পর ব্যবহার iter++মধ্যে erase()কল।


4
আমি বিভ্রান্ত; আপনি কেন (... ...) এর পরিবর্তে (...) ব্যবহার করবেন? এছাড়াও, এটি সম্ভবত কাজ করার সময়, .rase পরেরটির একটি পুনরাবৃত্তি ফেরত দেয় না? সুতরাং মনে হচ্ছে if (কিছু শর্ত) ব্লগটি সবচেয়ে সামঞ্জস্যপূর্ণ হওয়ার জন্য iter = aMap.erase (iter) হওয়া উচিত। সম্ভবত আমি কিছু মিস করছি? আপনার কিছু অভিজ্ঞতার আমার অভাব আছে।
ট্যাক্সিলিয়ান

86
দ্রষ্টব্য, সি ++ 11-এ সমস্ত এসোসিয়েটিভ পাত্রে, সহ mapপরবর্তী আইট্রেটরটি এখান থেকে ফিরে আসুন erase(iter)। এটি করা অনেক ক্লিনার iter = erase( iter )
পোটোসওয়টার

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

4
@ টেক্সিলিয়ান আরও গুরুত্বপূর্ণ: 'for' দিয়ে, আপনি আপনার পুনরাবৃত্ত সংজ্ঞাটি লুপের আওতায় রাখতে পারেন, সুতরাং এটি আপনার প্রোগ্রামের বাকী অংশের সাথে বিশৃঙ্খলা সৃষ্টি করবে না।
18:34

1
@ অ্যাথোস প্রশ্নটি নিষ্ক্রিয় কণ্ঠে বর্ণিত, "এটি প্রস্তাবিত।" কোনও সার্বজনীন সুপারিশ নেই। আমি মনে করি আমার শেষ মন্তব্যটি সবচেয়ে সোজা উপায়। এটিতে পুনরুক্তিযুক্ত ভেরিয়েবলের দুটি অনুলিপি জড়িত যা এখানে কেউ উল্লেখ করার সাথে সাথে সামান্য দক্ষতা হারাবে। এটি আপনার কল যা আপনার জন্য উপযুক্ত।
পোটোসওয়টার

75

ધો: :: মানচিত্রের (এবং অন্যান্য পাত্রে) মুছে ফেলা

আমি এই খুব জিনিস জন্য নিম্নলিখিত টেমপ্লেট ব্যবহার।

namespace stuff {
  template< typename ContainerT, typename PredicateT >
  void erase_if( ContainerT& items, const PredicateT& predicate ) {
    for( auto it = items.begin(); it != items.end(); ) {
      if( predicate(*it) ) it = items.erase(it);
      else ++it;
    }
  }
}

এটি কোনও কিছুই ফিরিয়ে দেবে না, তবে এটি স্ট্যান্ড :: ম্যাপ থেকে আইটেমগুলি সরিয়ে ফেলবে।

ব্যবহারের উদাহরণ:

// 'container' could be a std::map
// 'item_type' is what you might store in your container
using stuff::erase_if;
erase_if(container, []( item_type& item ) {
  return /* insert appropriate test */;
});

দ্বিতীয় উদাহরণ (আপনি একটি পরীক্ষার মান পাস করতে পারবেন):

// 'test_value' is value that you might inject into your predicate.
// 'property' is just used to provide a stand-in test
using stuff::erase_if;
int test_value = 4;  // or use whatever appropriate type and value
erase_if(container, [&test_value]( item_type& item ) {
  return item.property < test_value;  // or whatever appropriate test
});

3
@ কোডএংগ্রিক ধন্যবাদ - এটি আমার কাছে সর্বদা অদ্ভুত বলে মনে হয়েছিল যে এটি ইতিমধ্যে বিদ্যমান ছিল না std। আমি বুঝতে পারি এটি কেন সদস্য নয় std::mapতবে আমি মনে করি এটির মতো কিছু স্ট্যান্ডার্ড লাইব্রেরিতে থাকা উচিত।
আয়রন উদ্ধারকারী

3
C ++ 20std::map এবং অন্যদের জন্য যুক্ত করা হবে ।
রই ড্যান্টন


3

আমি এই ডকুমেন্টেশনটি দুর্দান্ত এসজিআই এসটিএল রেফারেন্স থেকে পেয়েছি :

মানচিত্রে একটি গুরুত্বপূর্ণ সম্পত্তি রয়েছে যা একটি মানচিত্রে একটি নতুন উপাদান সন্নিবেশ করানো বিদ্যমান উপাদানগুলিকে নির্দেশ করে এমন পুনরাবৃত্তিকে অবৈধ করে না। মানচিত্র থেকে কোনও উপাদান মুছে ফেলাও পুনরাবৃত্তকারীদের জন্য অবশ্যই কোনও পুনরুক্তিকারীকে অবৈধ করে না যা মুছে ফেলা হচ্ছে এমন উপাদানটির দিকে নির্দেশ করে।

সুতরাং, আপনার যে পুনরাবৃত্তিকে মুছে ফেলতে হবে সেই উপাদানটির দিকে ইঙ্গিত করছে অবশ্যই অবৈধ হবে। এরকম কিছু করুন:

if (some condition)
{
  iterator here=iter++;
  aMap.erase(here)
}

3
এটি মূল কোড থেকে আলাদা নয়। এটি ++ বৃদ্ধি করে পুনরাবৃত্তির পরে পুনরবৃদ্ধির পূর্বে উপাদানটির দিকে ইশারা করে একটি পুনরাবৃত্তি প্রদান করে।
স্টিভ ফলি

তবে ইটারটি অবৈধ হবে না যেহেতু আমরা তারপরে এখানে অবস্থানে মুছব
1800 তথ্য

@ 1800INFORMATION: একটি ফাংশন কল প্রবেশ করানো একটি সিকোয়েন্স পয়েন্ট, ইনক্রিমেন্ট সাইড এফেক্ট বলার আগে মূল্যায়ন eraseকরা হয়। সুতরাং তারা অবশ্যই সমতুল্য। তবুও, আমি আপনার সংস্করণটিকে মূলের চেয়ে দৃ strongly়ভাবে পছন্দ করব prefer
পিটারচেন

এটি অ্যারে বা ভেক্টরের জন্য কাজ করে তবে স্টল মানচিত্রে অপ্রত্যাশিত ফলাফলের কারণ হবে।
শিকারি_টেক

2

মূল কোডটিতে কেবল একটি সমস্যা রয়েছে:

for(; iter != endIter; ++iter)
{
    if(Some Condition)
    {
        // is it safe ?
        aMap.erase(iter++);
    }
}

এখানে iterলুপের জন্য একবার এবং মুছে ফেলার সময় আরও একবার বৃদ্ধি করা হয়েছে যা সম্ভবত কিছু অসীম লুপে শেষ হবে।



1

নীচের নোটগুলি থেকে:

http://www.sgi.com/tech/stl/PairAssociativeContainer.html

একটি পেয়ার অ্যাসোসিয়েটিভ কনটেইনার পরিবর্তনীয় পুনরাবৃত্তকারী সরবরাহ করতে পারে না (তুচ্ছ আইট্রেটার প্রয়োজনীয়তায় সংজ্ঞায়িত), কারণ কোনও পরিবর্তনীয় পুনরাবৃত্তির মান ধরণ অবশ্যই অর্পণযোগ্য হতে হবে, এবং জোড়টি বরাদ্দযোগ্য নয়। যাইহোক, একটি পেয়ার অ্যাসোসিয়েটিভ কনটেইনার পুনরাবৃত্তকারীগুলিকে সরবরাহ করতে পারে যা সম্পূর্ণ ধ্রুবক নয়: পুনরাবৃত্তকারী যেমন অভিব্যক্তি (* i)। সেকেন্ড = ডি বৈধ।


1

প্রথম

মানচিত্রে একটি গুরুত্বপূর্ণ সম্পত্তি রয়েছে যা একটি মানচিত্রে একটি নতুন উপাদান সন্নিবেশ করানো বিদ্যমান উপাদানগুলিকে নির্দেশ করে এমন পুনরাবৃত্তিকে অবৈধ করে না। মানচিত্র থেকে কোনও উপাদান মুছে ফেলাও পুনরাবৃত্তকারীদের জন্য অবশ্যই কোনও পুনরুক্তিকারীকে অবৈধ করে না যা মুছে ফেলা হচ্ছে এমন উপাদানটির দিকে নির্দেশ করে।

দ্বিতীয়ত, নিম্নলিখিত কোডটি ভাল

for(; iter != endIter; )
{
    if(Some Condition)
    {
        aMap.erase(iter++);
    }
    else
    {
        ++iter;
    }
}

কোনও ফাংশন কল করার সময়, সেই ফাংশনে কল করার আগে প্যারামিটারগুলি মূল্যায়ন করা হয়।

সুতরাং কলটি মোছার আগে যখন ইটার ++ মূল্যায়ন করা হয় তখন পুনরাবৃত্তির ++ অপারেটর বর্তমান আইটেমটি ফিরিয়ে দেবে এবং কল করার পরে পরবর্তী আইটেমটির দিকে নির্দেশ করবে।


1

আইএমএইচও এর remove_if()সমতুল্য নেই।
আপনি কোনও মানচিত্র পুনরায় অর্ডার করতে পারবেন না।
সুতরাং remove_if()আপনি যে কলটি করতে পারেন তার শেষে আপনার আগ্রহের জোড়গুলি রাখতে পারবেন না erase()


এটা সত্যিই দুর্ভাগ্যজনক।
allyourcode

1

আয়রন ত্রাণকর্তার উত্তরের উপর ভিত্তি করে স্টাড ফাংশনাল নেওয়ার পুনরাবৃত্তির রেখাগুলির জন্য যারা আরও একটি পরিসীমা সরবরাহ করতে চান তাদের জন্য।

template< typename ContainerT, class FwdIt, class Pr >
void erase_if(ContainerT& items, FwdIt it, FwdIt Last, Pr Pred) {
    for (; it != Last; ) {
        if (Pred(*it)) it = items.erase(it);
        else ++it;
    }
}

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


1
"আন্ডারস্কোর দিয়ে শুরু করা শনাক্তকারীগুলি এবং তারপরে একটি বড় মামলার চিঠিটি প্রয়োগের মাধ্যমে সমস্ত ব্যবহারের জন্য সংরক্ষিত থাকে।"
YSC

0

স্টিভ ফোলির উত্তর আমি আরও দক্ষ বলে মনে করি।

এখানে আরও একটি সহজ-তবে-কার্যকর দক্ষ সমাধান :

সমাধানটি আমাদের remove_copy_ifযে মানগুলি একটি নতুন ধারক হিসাবে কপি করতে চায় তা ব্যবহার করে, তারপরে নতুন ধারকগুলির সাথে মূল পাত্রে থাকা সামগ্রীগুলি অদলবদল করে:

std::map<int, std::string> aMap;

...
//Temporary map to hold the unremoved elements
std::map<int, std::string> aTempMap;

//copy unremoved values from aMap to aTempMap
std::remove_copy_if(aMap.begin(), aMap.end(), 
                    inserter(aTempMap, aTempMap.end()),
                    predicate);

//Swap the contents of aMap and aTempMap
aMap.swap(aTempMap);

2
তা অদক্ষ মনে হচ্ছে।
allyourcode

0

আপনি যদি 2 এর চেয়ে বেশি কী সহ সমস্ত উপাদান মুছতে চান তবে সর্বোত্তম উপায়

map.erase(map.upper_bound(2), map.end());

কোনও রেসেটের জন্য নয়, কেবলমাত্র রেঞ্জের জন্য কাজ করে।


0

আমি এই মত ব্যবহার

 std::map<int, std::string> users;    
 for(auto it = users.begin(); it <= users.end()) {
    if(<condition>){
      it = users.erase(it);
    } else {
    ++it;
    }
 }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.