আমি সূচি অনুসারে স্ট্যান্ড :: ভেক্টর <> থেকে কোনও উপাদান কীভাবে মুছব?


508

আমার একটি স্টাড :: ভেক্টর <int> আছে, এবং আমি n'th উপাদানটি মুছতে চাই। আমি কেমন করে ঐটি করি?

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);

4
Std :: deque ব্যবহার করা বিবেচনা করুন যা উভয় প্রান্তে সন্নিবেশ এবং মুছে ফেলা সরবরাহ করে।
দারিও

40
না, ডেক ব্যবহার করা বিবেচনা করবেন না কারণ আপনি কোনও উপাদান মুছতে পারেন, এটি সত্যই খারাপ পরামর্শ। আপনি কেন ডেক বা ভেক্টর ব্যবহার করতে চাইতে পারেন তার পুরো কারণ রয়েছে। এটি সত্য যে কোনও ভেক্টর থেকে কোনও উপাদান মুছে ফেলা ব্যয়বহুল হতে পারে - উদাহরণস্বরূপ যদি ভেক্টর বড় হয় তবে আপনি যে পোষ্ট কোড উদাহরণটি পোস্ট করেছেন তার থেকে ভেক্টরের চেয়ে কোনও ডেকু আরও ভাল হবে বলে মনে করার কোনও কারণ নেই।
পেঁচা 21

6
উদাহরণস্বরূপ, যদি আপনার কোনও গ্রাফিকাল অ্যাপ্লিকেশন থাকে যেখানে আপনি ইন্টারেক্টিভভাবে জিনিসগুলি সন্নিবেশ / সরিয়ে ফেলেন এমন জিনিসের একটি "তালিকা" প্রদর্শন করেন তবে সেগুলি প্রদর্শন করার জন্য আপনি প্রতি সেকেন্ডে 50-100 বার তালিকার মধ্য দিয়ে চলেছেন এবং আপনি কিছু সংযোজন / মুছে ফেলা বিবেচনা করুন প্রতি মিনিটে বার। সুতরাং ভ্যাক্টর হিসাবে "তালিকা" প্রয়োগ করা মোট দক্ষতার ক্ষেত্রে সম্ভবত একটি ভাল বিকল্প।
মিশেল বিলাউড

উত্তর:


705

একটি একক উপাদান মুছতে, আপনি এটি করতে পারেন:

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);

অথবা, একবারে একাধিক উপাদান মুছতে:

// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);

50
লক্ষণীয় বাইনারি operator+হয় না অগত্যা অন্যান্য ধারক ধরনের iterators জন্য সংজ্ঞায়িত মত list<T>::iterator(আপনি ব্যবহার করতে পারবেন না list.begin() + 2একটি অন std::list, আপনি ব্যবহার করতে হবে std::advanceযে)
bobobobo

আপনি কি বলছেন যে "+1" হ'ল প্রথম উপাদান মাইভেক্টর [0] বা আসল অবস্থান মাইভেক্টর [1]
কার্ল মরিসন

2
অগ্রিম সাথে আপনাকে অবশ্যই একটি চলকতে পুনরুক্তি সংরক্ষণ করতে হবে। আপনি যদি std :: ব্যবহার করেন তবে আপনি এটি এক লাইনে করতে পারেন: vec.erase (পরের (শুরু (ভিসি), 123));
দানি

8
যারা উত্তর দিয়েছেন তাদের সবাইকে ধন্যবাদ। কোনও শ্রেণি নকশার বিষয়ে আমাদের কী ভাবা উচিত যখন কোনও উপাদান মুছে ফেলার মতো সাধারণ ক্রিয়াকলাপের জন্য স্ট্যাকওভারফ্লোতে আসা দরকার?
পিয়েরে

5
@ পিয়ার কারণ কোনও নির্দিষ্ট উপাদানের সংখ্যাসূচক সূচক অ্যাক্সেসের প্রাথমিক মডেল নয়, পুনরাবৃত্তিকারী । সমস্ত ফাংশন যা কোনও পাত্রে উপাদানগুলি দেখায় সেগুলি ধারকটির পুনরাবৃত্তকারী ব্যবহার করে। যেমনstd::find_if
কালেথ

212

স্ট্যান্ড :: ভেক্টর মোছার পদ্ধতিটি অতিরিক্ত লোড হয়েছে, সুতরাং কল করা সম্ভবত এটি আরও পরিষ্কার

vec.erase(vec.begin() + index);

যখন আপনি কেবল একটি একক উপাদান মুছতে চান।


3
তবে সমস্যাটি প্রদর্শিত হচ্ছে আপনার কাছে কতগুলি উপাদান রয়েছে appears
জাইএক্স 2000

15
যদি কেবল একটি উপাদান থাকে তবে সূচক 0 হয় এবং তাই আপনি vec.begin()যা বৈধ তা পান।
আন কুইন

28
আমি আশা করি যে কেউ উল্লেখ করেছেন যে vec.erase(0)এটি কাজ করে না, তবে vec.erase(vec.begin()+0)(বা +0 ব্যতীত) কাজ করে না। অন্যথায় আমার কোনও মিল নেই ফাংশন কল, যার কারণেই আমি এখানে এসেছি
qrtLs

নাল পয়েন্টার ধ্রুবক হিসাবে ব্যাখ্যা করা vec.erase(0)যদি 0ঘটতে থাকে তবে @QrtL গুলি আসলে সংকলন করতে পারে ...
এলএফ

57
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
    std::vector<T>::iterator it = vec.begin();
    std::advance(it, pos);
    vec.erase(it);
}

2
সর্বাধিক, এই ফাংশনটি কীটির চেয়ে আরও ভাল করে তোলে: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }আমি এটির চেয়ে ভাল বলছি না, কেবল ব্যক্তিগত আগ্রহের কথা জিজ্ঞাসা করছি এবং এই প্রশ্নটি পেতে পারে তার সেরা ফলাফলটি ফিরে আসতে।

13
@ জোয়েভজি: যেহেতু একটি vector<T>::iteratorএলোমেলো অ্যাক্সেস পুনরুক্তিকারী, তাই আপনার সংস্করণটি বেশ ভাল এবং সম্ভবত কিছুটা পরিষ্কার। তবে ম্যাক্স পোস্ট করা সংস্করণটি ঠিকঠাক কাজ করা উচিত যদি আপনি ধারকটিকে অন্য কোনওটিতে পরিবর্তন করেন যা এলোমেলো-অ্যাক্সেস পুনরুক্তি সমর্থন করে না
লিলি ব্যালার্ড

2
এটি ইমো আরও ভাল উত্তর, কারণ এটি অন্যান্য ধারক বিন্যাসেও প্রযোজ্য। আপনি স্ট্যান্ড :: পরবর্তী () ব্যবহার করতে পারেন।
বিম

এটি আরও ভাল পদ্ধতির যেহেতু এটি ধারকটির অভ্যন্তরের উপর নির্ভর করে না।
বার্তোসকেপিপি

std :: অগ্রিম কেবল তখনই প্রয়োজন হয় যদি আপনি ভাবেন যে এটি কোনও ভেক্টর অর্থাৎ একটি তালিকা হবে না। তবে আপনি যেমন এখানে উল্লেখ করেছেন, অপারেটরটি কি সহজ হবে না? এই স্ট্যাকওভারফ্লো.com/ প্রশ্নগুলি / 1668088/ … অনুযায়ী অপারেটর + এর সাথে পারফরম্যান্সে একটি সম্ভাব্য লাভ রয়েছে
নীল ম্যাকগিলের

14

eraseপদ্ধতি দুইভাবে ব্যবহার করা হবে:

  1. একক উপাদান মুছে ফেলা হচ্ছে:

    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
  2. উপাদানগুলির পরিসীমা মুছে ফেলা:

    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element

7
গৃহীত উত্তরের প্রায় 7 বছর পরে এটি একটি সদৃশ উত্তর। দয়া করে এটি করবেন না।
অ্যালাস্টারজি

10

আসলে, eraseফাংশনটি দুটি প্রোফাইলের জন্য কাজ করে:

  • একটি একক উপাদান অপসারণ করা হচ্ছে

    iterator erase (iterator position);
  • উপাদানগুলির একটি ব্যাপ্তি অপসারণ করা

    iterator erase (iterator first, iterator last);

যেহেতু std :: vec.begin () কনটেইনারটির সূচনা করে এবং যদি আমরা আমাদের ভেক্টরে ith উপাদানটি মুছতে চাই, তবে আমরা এটি ব্যবহার করতে পারি:

vec.erase(vec.begin() + index);

আপনি যদি ঘনিষ্ঠভাবে লক্ষ্য করেন তবে, vec.begin () আমাদের ভেক্টরের প্রারম্ভিক অবস্থানের জন্য কেবলমাত্র একটি পয়েন্টার এবং এতে i এর মান যুক্ত করে পয়েন্টারটিকে i পজিশনে বৃদ্ধি করে, সুতরাং পরিবর্তে আমরা আইথ উপাদানটিতে পয়েন্টারটি অ্যাক্সেস করতে পারি:

&vec[i]

সুতরাং আমরা লিখতে পারি:

vec.erase(&vec[i]); // To delete the ith element

6
-1 শেষ লাইনটি কমপক্ষে সংকলন করে না (কমপক্ষে VS2017 এ)। কোডটি ধরে নিয়েছে যে ভেক্টর :: এট্রেটর একটি কাঁচা পয়েন্টার থেকে স্পষ্টতই গঠনযোগ্য, যা মানক দ্বারা প্রয়োজনীয় নয়।
কৌতূহল জর্জে

1
এটি বিশেষত ডিবাগ পুনরাবৃত্তিকারীদের ক্ষেত্রে সত্য
নিশান্ত সিং

9

যদি আপনার কোনও অ-নিরক্ষিত ভেক্টর থাকে তবে আপনি এটি আনর্ডারড হওয়া এবং আপনি সিপিপিসন-এ ড্যান হিগিন্সের কাছ থেকে দেখেছি এমন কিছু ব্যবহার করতে পারেন advantage

template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
    if ( inIndex < inContainer.size() )
    {
        if ( inIndex != inContainer.size() - 1 )
            inContainer[inIndex] = inContainer.back();
        inContainer.pop_back();
        return true;
    }
    return false;
}

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


আমি মনে করি ভেক্টরটি আনর্ডার্ড না করা থাকলে এটিই সেরা উত্তর। এটি অনুমানের উপর নির্ভর করে না যা iterator + indexআপনাকে সেই সূচকটিতে পুনরাবৃত্তি অবস্থানটি ফিরিয়ে দেবে, যা সমস্ত পুনরাবৃত্তিযোগ্য ধারকগুলির ক্ষেত্রে সত্য নয়। এটি ব্যাক পয়েন্টারের সুবিধা গ্রহণ করে লিনিয়ার পরিবর্তে স্থির জটিলতা।
theferrit32

1
এটিকে পুরোপুরি স্ট্যান্ড লিবিতে যুক্ত করা দরকার unordered_removeএবং unordered_remove_if... যতক্ষণ না এটি হয়েছে এবং আমি এটি মিস করেছি, যা এই দিনগুলিতে বেশি বেশি
উইল ক্র্যাফোর্ড

যদি কোনও অনুলিপি-অ্যাসাইনমেন্টের পরিবর্তে মুভ-অ্যাসাইনমেন্ট বা অদলবদল করার পরামর্শ দেয়।
কার্স্টেন এস

std::removeকনটেইনারটি পুনরায় অর্ডার করে যাতে সরানো সমস্ত উপাদানগুলি শেষে হয়, আপনি যদি সি ++ 17 ব্যবহার করেন তবে ম্যানুয়ালি এটি করার দরকার নেই
কেইথ

@ কীভাবে std::removeসাহায্য করে? সিপ্রেফারেন্স দাবি করে যে এমনকি সি ++ 17 এও সমস্ত removeওভারলোডের জন্য একটি শিকারের প্রয়োজন হয়, এবং কেউই সূচক নেয় না।
পল ডু বোইস

4

আপনি যদি বৃহত্তর ভেক্টর (আকার> 100,000) এর সাথে কাজ করেন এবং প্রচুর উপাদান মুছতে চান তবে আমি এই জাতীয় কিছু করার পরামর্শ দিচ্ছি:

int main(int argc, char** argv) {

    vector <int> vec;
    vector <int> vec2;

    for (int i = 0; i < 20000000; i++){
        vec.push_back(i);}

    for (int i = 0; i < vec.size(); i++)
    {
        if(vec.at(i) %3 != 0)
            vec2.push_back(i);
    }

    vec = vec2;
    cout << vec.size() << endl;
}

কোডটি ভিসিতে প্রতিটি সংখ্যা নেয় যা 3 দ্বারা ভাগ করা যায় না এবং এটি ভিস 2 তে অনুলিপি করে। এরপরে এটি ভিসি-তে কপি করে। এটি বেশ দ্রুত। 20,000,000 উপাদানগুলি প্রক্রিয়া করতে এই অ্যালগরিদমটি কেবল 0.8 সেকেন্ড সময় নেয়!

মুছে ফেলার পদ্ধতিতেও আমি একই কাজ করেছি এবং এতে প্রচুর এবং প্রচুর সময় লাগে:

Erase-Version (10k elements)  : 0.04 sec
Erase-Version (100k elements) : 0.6  sec
Erase-Version (1000k elements): 56   sec
Erase-Version (10000k elements): ...still calculating (>30 min)

6
কিভাবে এই প্রশ্নের উত্তর দেয়?
রেজিস পোর্টালেজ 12'16

4
আকর্ষণীয়, তবে প্রশ্নের সাথে প্রাসঙ্গিক নয়!
রডি

কোনও স্থানের অ্যালগরিদম দ্রুততর হবে না?
ব্যবহারকারী 202729

2
এটি স্টডি :: অপসারণ_আইফ (+ মুছে ফেলা)
রিয়াদ

3

কোনও উপাদান মোছার জন্য নিম্নলিখিত উপায়টি ব্যবহার করুন:

// declaring and assigning array1 
std:vector<int> array1 {0,2,3,4};

// erasing the value in the array
array1.erase(array1.begin()+n);

একটি জন্য আরো বিস্তৃত ওভারভিউ আপনি এখানে যেতে পারেন: http://www.cplusplus.com/reference/vector/vector/erase/


Cppreferences ব্যবহার বিবেচনা করুন । দেখুন এই , এই , ইত্যাদি
এলএফ

3

আমি এটি পড়ার পরামর্শ দিই যেহেতু আমি বিশ্বাস করি এটিই আপনি খুঁজছেন। https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

যদি আপনি উদাহরণস্বরূপ ব্যবহার

 vec.erase(vec.begin() + 1, vec.begin() + 3);

আপনি ভেক্টরের এন-তম উপাদানটি মুছবেন তবে যখন আপনি দ্বিতীয় উপাদানটি মুছবেন তখন ভেক্টরের অন্যান্য সমস্ত উপাদান স্থানান্তরিত হবে এবং ভেক্টরের আকার -1 হবে। ভেক্টরের আকার () হ্রাস হওয়ায় আপনি যদি ভেক্টরের মধ্য দিয়ে লুপ করেন তবে এটি সমস্যা হতে পারে। আপনার যদি এইর মতো সমস্যা থাকে তবে স্ট্যান্ডার্ড সি ++ লাইব্রেরিতে বিদ্যমান অ্যালগরিদম ব্যবহার করার পরামর্শ দেওয়া হয়েছে। এবং "অপসারণ" বা "মুছে ফেলা"

আশা করি এটি সাহায্য করেছে


0

পূর্ববর্তী উত্তরগুলি ধরে নিয়েছে যে আপনার কাছে সর্বদা স্বাক্ষরিত সূচি থাকে। দুঃখের বিষয়, সূচকের জন্য std::vectorব্যবহার size_type, এবংdifference_type পুনরুক্তিকারীর গাণিতিক জন্য, তাই তারা একসঙ্গে কাজ করে না যদি আপনি "-Wconversion" আছে এবং এর বন্ধুদের সক্ষম করা হয়েছে। স্বাক্ষরিত এবং স্বাক্ষরযুক্ত উভয়ই পরিচালনা করতে সক্ষম হওয়ায় এই প্রশ্নের উত্তর দেওয়ার আরও একটি উপায়:

মুছে ফেলার জন্য:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
    v.erase(iter);
}

নিতে:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);

    auto val = *iter;
    v.erase(iter);

    return val;
}

0

এটি করার আরও একটি উপায় এখানে আপনি যদি কোনও উপাদানটিকে ভেক্টরের মান সহ এটি সন্ধান করে মুছতে চান, আপনার কেবল ভেক্টর এ এটি করা দরকার।

vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

এটি এখান থেকে আপনার মান সরিয়ে ফেলবে। ধন্যবাদ


0

এ কেমন?

void squeeze(vector<int> &v)
{
    int j = 0;
    for (int i = 1; i < v.size(); i++)
        if (v[i] != v[j] && ++j != i)
            v[j] = v[i];
    v.resize(j + 1);
}

-4

দ্রুততম উপায় (সময়ের জটিলতায় প্রোগ্রামিং প্রতিযোগিতার জন্য () = ধ্রুবক)

1 সেকেন্ডে 100 এম আইটেম মুছতে পারে;

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it);

এবং সর্বাধিক পঠনযোগ্য উপায়: vec.erase(vec.begin() + pos);


2
এটি খুব অ-বহনযোগ্য; এটি libstdc ++ নিয়ে কাজ করবে, তবে libc ++ নয়, এবং MSVC- এর সাথে নয়। vector<int>::iteratorঅগত্যা একইরকম নয়int *
মার্শাল ক্লো

2
এটি বিরক্তিকর, আমি মনে করি আমি এটি কাজ করা বন্ধ করতে libstdc ++ পরিবর্তন করব।
জোনাথন ওয়েকেলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.