আমি একটি স্টাইল ভেক্টর থেকে একটি নির্দিষ্ট মান সহ কীভাবে একটি আইটেম সরিয়ে ফেলব?


145

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


2
আমি জানি আমি এর আগেও বেশ কয়েকবার উল্লেখ করেছি তবে স্কট মেয়ারের বইয়ের কার্যকর এসটিএল এই গোছাটিকে পরিষ্কার উপায়ে .েকে দিয়েছে।
রব ওয়েলস

1
সম্পর্কিত: stackoverflow.com/questions/3385229/...
bobobobo

এই আপনি একটি আকর্ষণীয় পড়া হতে পারে en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
sergiol

উত্তর:


165

std::removeকন্টেইনারটি থেকে আসলে উপাদানটি মুছবে না, তবে এটি নতুন প্রান্তটি পুনরুদ্ধার করবে যা এখন ধারকটির শেষে container_type::eraseথাকা অতিরিক্ত উপাদানগুলির রিয়েল অপসারণ করতে পাস করা যেতে পারে :

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());

3
এই সমস্ত-ইন-ওয়ান-স্টেটমেন্ট ফর্মটি কি সংক্রমণের ভিত্তিতে সংকলকটি আর্গুমেন্টগুলি মূল্যায়নের উপর নির্ভর করে, বা vec.end()কল করার উভয় পক্ষেই একইরূপে গ্যারান্টিযুক্ত std::remove? এটি ওয়েবের অন্যান্য অংশগুলি পড়ার ক্ষেত্রে আমার কাছে মনে হয় এটি নিরাপদ তবে এটি স্পষ্টভাবে বলা উচিত।
ডিএমকেকে --- প্রাক্তন মডারেটর বিড়ালছানা

1
এটা ভাল. ফলাফল vec.end()একই হতে হবে না; এটি ঠিক সঠিক হওয়া দরকার (যা এটি)।
জিম বাক

8
vec.end()একই হওয়া দরকার, তবে এটি ঠিক আছে কারণ std::removeএটি পরিবর্তন করে না। যদি এটি এটিকে পরিবর্তন করে (এবং পুরাতন মানকে অবৈধ করে তোলে) তবে সমস্যা হবে: প্যারামিটারগুলির মূল্যায়নের ক্রমটি অনির্দিষ্ট vec.end()। এটি একই রকম হওয়ার কারণ, std::removeধারকটির আকার পরিবর্তন করে না, এটি কেবল সামগ্রীগুলি চারপাশে সরিয়ে দেয়।
স্টিভ জেসোপ

2
আমি এই প্রশ্নটি গুরুত্বপূর্ণ খুঁজে পেয়েছি, যেহেতু আমার একই সমস্যা। তবে, আমার ভিজ্যুয়াল স্টুডিওতে std::removeকেবল একটি যুক্তিই রয়েছে; যে const char *_Filename। আমাকে কোন পদ্ধতিতে কল করতে হবে?
ভিক্টর

15
এটির একটি সংস্করণ removeএটি কোনও ফাইল মুছে দেয়। ধারকগুলির সাথে ডিলের <algorithm>সেই সংস্করণটি অ্যাক্সেস করার জন্য আপনাকে অন্তর্ভুক্ত করতে হবে remove
জিম বাক

64

আপনি যদি কোনও আইটেম সরাতে চান তবে নিম্নলিখিতগুলি আরও কিছুটা কার্যকর হবে।

std::vector<int> v;


auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
    v.erase(it);

অথবা আপনি যদি আদেশটি বিবেচনা না করেন তবে আপনি আইটেমগুলি সরিয়ে নিয়ে যাওয়া উপেক্ষা করতে পারবেন:

std::vector<int> v;

auto it = std::find(v.begin(), v.end(), 5);

if (it != v.end()) {
  using std::swap;

  // swap the one to be removed with the last element
  // and remove the item at the end of the container
  // to prevent moving all items after '5' by one
  swap(*it, v.back());
  v.pop_back();
}

3
নোট করুন এটি উপস্থিত থাকলে আইটেমের সদৃশগুলি সরিয়ে ফেলবে না, যেখানে std :: মুছে ফেলা হবে -
ডেন-জেসন

15

আরম্ভ এবং শেষ পুনরুক্তি দিয়ে গ্লোবাল পদ্ধতি STD :: অপসারণটি ব্যবহার করুন এবং তারপরে উপাদানগুলি সরাতে std :: vector.erase ব্যবহার করুন।

নথিপত্র সংযোগগুলি
std :: অপসারণ http://www.cppreference.com/cppalgorithm/remove.html
এসটিডি :: vector.erase http://www.cppreference.com/cppvector/erase.html

std::vector<int> v;
v.push_back(1);
v.push_back(2);

//Vector should contain the elements 1, 2

//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);

//Erase the "removed" elements.
v.erase(newEnd, v.end());

//Vector should now only contain 2

আমার ত্রুটিটি নির্দেশ করার জন্য জিম বাককে ধন্যবাদ।


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

5

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

আপনি যদি নিবিড়ভাবে এই অপারেশনটি করে থাকেন তবে এই কারণে পরিবর্তে std :: সেট বিবেচনা করা উপযুক্ত worth


5

যদি আপনার কোনও অরসোর্টার্ড ভেক্টর থাকে তবে আপনি কেবল তখন শেষ ভেক্টর উপাদানটি দিয়েই সোয়াপ করতে পারেন resize()

একটি আদেশ ধারক সঙ্গে, আপনি সঙ্গে সেরা বন্ধ হবেন std::vector::erase()। মনে রাখবেন যে এখানে একটি std::remove()সংজ্ঞায়িত হয়েছে <algorithm>তবে এটি মুছে ফেলার কাজটি করে না। (সাবধানে ডকুমেন্টেশন পড়ুন)।


3

একটি সংক্ষিপ্ত সমাধান (যা আপনাকে ভেক্টরের নামটি 4 বার পুনরাবৃত্তি করতে বাধ্য করে না) বুস্টটি ব্যবহার করতে হবে:

#include <boost/range/algorithm_ext/erase.hpp>

// ...

boost::remove_erase(vec, int_to_remove);

Http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/references/algorithms/new/remove_erase.html দেখুন


3

থেকে C ++ 20 :

একটি অ-সদস্য ফাংশন চালু করা হয়েছে std::erase, যা ভেক্টর এবং ইনপুট হিসাবে মুছে ফেলার মান নেয়।

উদা:

std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);

2
শুধু তাই নয়, এটি প্রতিটি নির্দিষ্ট ধারকের জন্য ওভারলোড হয়!
হলি ব্ল্যাককিট 15'19

... এবং ধারক-নির্দিষ্ট বৈশিষ্ট্যগুলির সুবিধা গ্রহণ করে, যেমন map::erase!
এলএফ

2

প্রিডিকেট ব্যবহার করতে সক্ষম হতে স্ট্যান্ড :: অপসারণ_এটিও দেখুন ...

উপরের লিঙ্ক থেকে উদাহরণ এখানে:

vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);

copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
    // The output is "1 4 2 8 5 7"

vector<int>::iterator new_end = 
    remove_if(V.begin(), V.end(), 
              compose1(bind2nd(equal_to<int>(), 0),
                       bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]

copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
    // The output is "1 5 7".

2
এই পোস্টে আরও বিস্তারিত যোগ করুন। এটি যেমন দাঁড়িয়ে আছে, এর বেশিরভাগ সামগ্রীর লিঙ্ক থেকে আসে এবং লিঙ্কটি কখনও ভেঙে গেলে তা হারিয়ে যাবে।
মিক ম্যাককালাম

বাইন্ড 2 ম বাস্তবের কী - (সি ++ 11 এ অবমূল্যায়ন) (সি ++ 17 এ সরিয়ে দেওয়া হয়েছে)
ইদন বনানী

0

আপনি যদি কোনও অতিরিক্ত ছাড়াই এটি করতে চান তবে অন্তর্ভুক্ত করুন:

vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
    IComponent* juggler;

    if (componentToRemove != NULL)
    {
        for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
        {
            if (componentToRemove == myComponents[currComponentIndex])
            {
                //Since we don't care about order, swap with the last element, then delete it.
                juggler = myComponents[currComponentIndex];
                myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
                myComponents[myComponents.size() - 1] = juggler;

                //Remove it from memory and let the vector know too.
                myComponents.pop_back();
                delete juggler;
            }
        }
    }
}

0

দুটি উপায় রয়েছে যার মাধ্যমে আপনি বিশেষ করে কোনও জিনিস মুছতে ব্যবহার করতে পারেন। একটি ভেক্টর নিতে দিন

std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);

1) অ দক্ষ দক্ষ উপায়: যদিও এটি বেশ দক্ষ বলে মনে হচ্ছে তবে এটি মুছে ফাংশনটি উপাদানগুলিকে বিলম্বিত করে এবং সমস্ত উপাদানকে 1 দ্বারা বাম দিকে স্থানান্তরিত করে না তাই এর জটিলতা O (n ^ 2) হবে

std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
   if(*itr == value)
   { 
      v.erase(itr);
   }
   else
       ++itr;
}

2) দক্ষ উপায় (প্রস্তাবিত) : এটি ERASE - আইডিয়োম রিমুভ নামেও পরিচিত ।

  • std :: মুছে ফেলা প্রদত্ত পরিসরটিকে সমস্ত উপাদানগুলির সাথে একটি পরিসরে রূপান্তরিত করে যা ধারকটির শুরুতে স্থানান্তরিত প্রদত্ত উপাদানের সমান নয় compare
  • সুতরাং, আসলে মিলিত উপাদানগুলি সরাবেন না। এটি কেবল নন-ম্যাচটি শুরুতে স্থানান্তরিত করেছে এবং নতুন বৈধ প্রান্তে একটি পুনরুক্তি দেয়। এটি কেবল ও (এন) জটিলতার প্রয়োজন।

অপসারণ অ্যালগরিদমের ফলাফল:

10 20 30 50 40 50 

রিমোট টাইপের রিটার্নটি সেই ব্যাপ্তির নতুন প্রান্তে পুনরাবৃত্ত হয়।

template <class ForwardIterator, class T>
  ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);

এখন ভেক্টরের নতুন প্রান্ত থেকে পুরানো প্রান্ত পর্যন্ত উপাদানগুলি মুছতে ভেক্টরের মুছা ফাংশনটি ব্যবহার করুন। এটি ও (1) সময় প্রয়োজন।

v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );

সুতরাং এই পদ্ধতিটি ও (এন) এ কাজ করে


0

*

সি ++ সম্প্রদায় আপনার অনুরোধ শুনেছে :)

*

সি ++ ২০ এখন এটি করার সহজ উপায় সরবরাহ করে। এটি যেমন সহজ হয়:

#include <vector>
...
vector<int> cnt{5, 0, 2, 8, 0, 7};
std::erase(cnt, 0);

আপনার std :: মুছা এবং std :: মুছা_এফ পরীক্ষা করা উচিত

এটি কেবলমাত্র মানটির সমস্ত উপাদান সরিয়ে ফেলবে না (এখানে '0') এটি ও (এন) এ করবে সময়ের জটিলতায় । যা আপনি সবচেয়ে ভাল পেতে পারেন।

যদি আপনার সংকলক সি ++ 20 সমর্থন করে না, আপনার মুছে ফেলা মুছিয়া ব্যবহার করা উচিত :

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.