একটি ভেক্টর থেকে উপাদানগুলি মুছে ফেলা হচ্ছে


102

আমি মুছা পদ্ধতিটি ব্যবহার করে কোনও ভেক্টর থেকে একটি উপাদান সাফ করতে চাই। তবে এখানে সমস্যাটি হ'ল উপাদানটি ভেক্টরে একবারে আসার নিশ্চয়তা দেয় না। এটি একাধিকবার উপস্থিত হতে পারে এবং আমার সেগুলি সমস্ত পরিষ্কার করতে হবে। আমার কোডটি এরকম কিছু:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
    std::vector<int>::iterator iter = myNumbers_in.begin();
    std::vector<int>::iterator endIter = myNumbers_in.end();
    for(; iter != endIter; ++iter)
    {
        if(*iter == number_in)
        {
            myNumbers_in.erase(iter);
        }
    }
}

int main(int argc, char* argv[])
{
    std::vector<int> myNmbers;
    for(int i = 0; i < 2; ++i)
    {
        myNmbers.push_back(i);
        myNmbers.push_back(i);
    }

    erase(myNmbers, 1);

    return 0;
}

এই কোডটি স্পষ্টতই ক্র্যাশ হয়েছে কারণ আমি এর মাধ্যমে পুনরাবৃত্তি করার সময় ভেক্টরের শেষ পরিবর্তন করছি। এই অর্জন করার জন্য সবচেয়ে ভাল উপায় কি? অর্থাৎ ভ্যাক্টরের মাধ্যমে একাধিকবার পুনরাবৃত্তি করা বা ভেক্টরের আরও একটি অনুলিপি তৈরি না করে এটি করার কোনও উপায় আছে কি?

উত্তর:


169

মুছে ফেলা / মুছুন ব্যবহার করুন :

std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());

যা ঘটে তা হ'ল এর শুরুর দিকে remove( number_in) মুছে vectorফেলার মান থেকে পৃথককারী উপাদানগুলিকে সংযোগ করে এবং সেই ব্যাপ্তির পরে পুনরাবৃত্তিকে প্রথম উপাদানে ফিরিয়ে দেয়। তারপরে eraseএই উপাদানগুলি (যার মূল্য অনির্ধারিত) সরান।


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

20
স্কট মায়ার্স দ্বারা "কার্যকর এসটিএল: স্ট্যান্ডার্ড টেম্পলেট লাইব্রেরির আপনার ব্যবহারের উন্নতি করার 50 টি নির্দিষ্ট উপায়" বইয়ের আইটেম 32-এ মুছে ফেলা আইডিয়ামটি বর্ণনা করা হয়েছে।
আলেসান্দ্রো জ্যাকসন

4
@ বেঞ্জিনের কোনও আপডেটের দরকার নেই, যদি বস্তুর উপস্থিতি থাকে তবে এটি ধ্বংসকারীদের কল করবে।
মোটি

54
এসটিএল এর 'আইডিয়োম' আমাকে ছোট প্রকল্পগুলির জন্য পাইথন ব্যবহার করতে বাধ্য করে।
জোহানেস ওভারম্যান

4
@ লুইস ডিওন যা একজনকে পুনরায় ওভারলোড বোঝায়, আমি দুটি পুনরুক্তিকারী ওভারলোড ব্যবহার করছি
মোটি

54

কলিং ইরিজ পুনরাবৃত্তিকে অবৈধ করে দেবে, আপনি এটি ব্যবহার করতে পারেন:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
    std::vector<int>::iterator iter = myNumbers_in.begin();
    while (iter != myNumbers_in.end())
    {
        if (*iter == number_in)
        {
            iter = myNumbers_in.erase(iter);
        }
        else
        {
           ++iter;
        }
    }

}

অথবা আপনি স্ট্যান্ড :: অপসারণ_ফাই একসাথে একটি ফান্টর এবং স্ট্যান্ড :: ভেক্টর :: মুছতে ব্যবহার করতে পারেন :

struct Eraser
{
    Eraser(int number_in) : number_in(number_in) {}
    int number_in;
    bool operator()(int i) const
    {
        return i == number_in;
    }
};

std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), Eraser(number_in)), myNumbers.end());

এক্ষেত্রে আপনার নিজের ফান্টর লেখার পরিবর্তে আপনি স্ট্যান্ড :: অপসারণ ব্যবহার করতে পারেন :

std::vector<int> myNumbers;
myNumbers.erase(std::remove(myNumbers.begin(), myNumbers.end(), number_in), myNumbers.end());

সি ++ 11 এ আপনি কোনও ফান্টারের পরিবর্তে ল্যাম্বডা ব্যবহার করতে পারেন:

std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), [number_in](int number){ return number == number_in; }), myNumbers.end());

সি ++ ১ st তম :: পরীক্ষামূলক :: মুছে ফেলা এবং এসটিডি :: পরীক্ষামূলক :: মুছা_আইএফ পাওয়া যায়, সি ++ ২০ এ এগুলি (শেষ অবধি) স্ট্যান্ড :: মুছে ফেলা এবং স্টাড :: ইরেজ_আইফ নামকরণ করা হয়েছে :

std::vector<int> myNumbers;
std::erase_if(myNumbers, Eraser(number_in)); // or use lambda

বা:

std::vector<int> myNumbers;
std::erase(myNumbers, number_in);

4
আপনি যখন সমতুল্য ব্যবহার করতে পারেন তখন কেন নিজের ফান্টর ব্যবহার করবেন? :-P sgi.com/tech/stl/equal_to.html
ক্রিস বিদূষক-ইয়াং

4
যাইহোক, সাথে কল eraseকরা removeএটি করার আধ্যাত্মিক উপায়।
কনরাড রুডল্ফ

4
আমি মনে করি ঠিক তাই করে। তবে যদি একটি নিজস্ব ফান্টার আইরিক ব্যবহার করা হয় তবে তিনি মুছে ফেলা উচিত। বা শুধু
ফান্টার

4
+1 বানান-আউট কোড কেবলমাত্র একটি প্রোগ্রামিং প্রতিযোগিতায় আমাকে সহায়তা করেছিল, যখন "মুছে ফেলা মুছা আইডিয়ামটি ব্যবহার করেন" না।

13
  1. আপনি সূচক অ্যাক্সেস ব্যবহার করে পুনরাবৃত্তি করতে পারেন,

  2. ও (এন ^ 2) জটিলতা এড়াতে আপনি দুটি সূচক ব্যবহার করতে পারেন, i - বর্তমান টেস্টিং সূচক, জে - সূচক পরবর্তী আইটেম সংরক্ষণ করতে এবং চক্রের শেষে ভেক্টরের নতুন আকার।

কোড:

void erase(std::vector<int>& v, int num)
{
  size_t j = 0;
  for (size_t i = 0; i < v.size(); ++i) {
    if (v[i] != num) v[j++] = v[i];
  }
  // trim vector to new size
  v.resize(j);
}

এই ক্ষেত্রে আপনার পুনরাবৃত্তিকারীদের কোনও অবৈধকরণ নেই, জটিলতা হ'ল (এন), এবং কোডটি খুব সংক্ষিপ্ত এবং আপনাকে কিছু সহায়ক ক্লাস লেখার দরকার নেই, যদিও কিছু ক্ষেত্রে সহায়ক ক্লাসগুলি ব্যবহার করে আরও নমনীয় কোডে সুবিধা অর্জন করতে পারে।

এই কোডটি eraseপদ্ধতি ব্যবহার করে না , তবে আপনার কাজটি সমাধান করে।

খাঁটি স্টিল ব্যবহার করে আপনি নিম্নলিখিত পদ্ধতিতে এটি করতে পারেন (এটি মট্টির উত্তরের অনুরূপ):

#include <algorithm>

void erase(std::vector<int>& v, int num) {
    vector<int>::iterator it = remove(v.begin(), v.end(), num);
    v.erase(it, v.end());
}

4

আপনি কেন এটি করছেন তার উপর নির্ভর করে একটি স্টাডি :: সেট ব্যবহার করা স্ট্যান্ড :: ভেক্টরের চেয়ে ভাল ধারণা হতে পারে।

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

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


-1

প্রথম উপাদানটি মুছতে আপনি ব্যবহার করতে পারেন:

vector<int> mV{ 1, 2, 3, 4, 5 }; 
vector<int>::iterator it; 

it = mV.begin(); 
mV.erase(it); 

4
এটা প্রশ্ন ছিল না। আপনার 11 বছর পরে উত্তর প্রাসঙ্গিক বলে মনে হচ্ছে না, অমিত!
উইংস উইস্ট উইং
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.