একটি 'ফর' লুপ ব্যবহার করে একটি সি ++ ভেক্টরের মাধ্যমে আইট্রেট করুন


140

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

for(int i=0; i < vector.size(); i++){
   vector[i].doSomething();
}

আমি সি ++ এ না দেখার কোনও কারণ আছে কি? এটা কি খারাপ অভ্যাস?


1
লুপের জন্য কোনও কার্য নয়, সুতরাং এতে প্যারামিটারগুলি নেই (বা আর্গুমেন্টগুলি যা আপনি পাস করেন)। আপনি কিছু বলতে চান std::vector<int>::size_type i = 0;, যদিও, বা সম্ভবত std::vector<int>::iterator it = vector.begin();?
খ্রিস্ট

হুবহু, আমি যে উদাহরণগুলি দেখছি তার সবগুলিই সেভাবে লেখা।
ফ্লাইনে

4
জাভাতে, আমি প্রতিটি লুপের জন্য বা পুনরুক্তি ব্যবহারকারীর পছন্দ করব। সি ++ এর মতো অনেকটা আলাদা যদিও কিছুটা আলাদা সিনট্যাক্স।
জেসি গুড


10
এখানে বেশিরভাগ উত্তর সঠিকভাবে প্রশ্নটিকে ধরে ধরেছে: পুনরাবৃত্তি করার সবচেয়ে ভাল / সংক্ষিপ্ততম উপায় কী std::vector? , প্রকৃত প্রশ্নটি এখানে জিজ্ঞাসা করা হচ্ছে: আমি এর সি ++ না দেখানোর কোনও কারণ আছে কি? এটা কি খারাপ অভ্যাস? ওরফে আমি কেন সবসময় সি ++ তে কোড দেখতে পাই যা পুনরাবৃত্তির সময় পুনরুক্তি ব্যবহার করে std::vector?
অলোক

উত্তর:


92

আমি সি ++ এ এটি না দেখার কোনও কারণ আছে কি? এটা কি খারাপ অভ্যাস?

না এটি একটি খারাপ অনুশীলন নয়, তবে নিম্নলিখিত পদ্ধতিটি আপনার কোডকে কিছু নমনীয়তা দেয়

সাধারণত, প্রি-সি ++ 11 ধারক উপাদানগুলির মাধ্যমে পুনরাবৃত্তি করার কোড পুনরাবৃত্তকারী ব্যবহার করে, এরকম কিছু:

std::vector<int>::iterator it = vector.begin();

কারণ কোডটি আরও নমনীয় করে তোলে।

সমস্ত মানক গ্রন্থাগার পাত্রে সমর্থনকারী এবং পুনরাবৃত্তি সরবরাহ করে। যদি উন্নয়নের কোনও পরবর্তী সময়ে আপনাকে অন্য ধারকটিতে স্যুইচ করতে হয় তবে এই কোডটি পরিবর্তন করার দরকার নেই।

দ্রষ্টব্য: লিখিত কোড যা প্রতিটি সম্ভাব্য স্ট্যান্ডার্ড লাইব্রেরি ধারকটির সাথে কাজ করে মনে হয় তত সহজ নয়।


25
কেউ দয়া করে আমাকে ব্যাখ্যা করতে পারেন কেন এই বিশেষ ক্ষেত্রে / কোড স্নিপেটে আপনি ইন্ডেক্সিংয়ের উপর পুনরাবৃত্তিকারীদের পরামর্শ দেন? এই "নমনীয়তা" আপনি কী সম্পর্কে কথা বলছেন? ব্যক্তিগতভাবে, আমি পুনরাবৃত্তিকারীদের পছন্দ করি না, তারা কোডটি ফুলেছে - একই প্রভাবের জন্য টাইপ করার জন্য আরও অক্ষর। বিশেষত যদি আপনি ব্যবহার করতে না পারেন auto
ভায়োলেট জিরাফ

8
@ ভায়োলেটজিরাফ: পুনরাবৃত্তকারীদের ব্যবহার করার সময় খালি রেঞ্জগুলির মতো নির্দিষ্ট ক্ষেত্রে ভুল হওয়া কঠিন এবং কোডটি আরও ভার্জোজ .অবস্থাপিত এটি কোনও বিষয় বা ধারণা এবং পছন্দ, তাই এটি অবিচ্ছিন্নভাবে বিতর্কিত হতে পারে।
অলোক

9
আপনি কেবল পুনরাবৃত্তিকে কীভাবে ঘোষণা করবেন তা প্রদর্শন করবেন তবে লুপটি করতে কীভাবে এটি ব্যবহার করবেন ...?
আন্ডারস্কোর_ডে

116

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

লোকেরা vector.size()লুপিংয়ের উপায় বিবেচনা না করার কারণগুলি নিম্নলিখিত হতে পারে :

  1. size()লুপ অবস্থায় প্রতিবার কল করা সম্পর্কে বেহাল হওয়া । তবে হয় এটি একটি নন-ইস্যু বা এটি তুচ্ছভাবে সমাধান করা যেতে পারে
  2. করা উচিত ছিল std::for_each()বেশি forলুপ নিজেই
  3. পরবর্তীতে কনটেইনারটি std::vectorঅন্য একটিতে পরিবর্তন করা (যেমন map, list) লুপিং পদ্ধতিতে পরিবর্তনও দাবি করবে, কারণ প্রতিটি কন্টেইনার সমর্থন size()শৈলী লুপিং নয়

সি ++ 11 কনটেইনারগুলির মধ্য দিয়ে চলার জন্য একটি ভাল সুবিধা সরবরাহ করে। একে বলা হয় "লুপের জন্য রেঞ্জ ভিত্তিক লুপ" (বা জাভাতে "লুপের জন্য বর্ধিত")।

সামান্য কোডের সাহায্যে আপনি পুরো (বাধ্যতামূলক!) মাধ্যমে অতিক্রম করতে পারেন std::vector:

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;

12
লুপের উপর ভিত্তি করে ব্যাপ্তির সামান্য অসুবিধা কেবল নোট করতে: আপনি এটি দিয়ে ব্যবহার করতে পারবেন না #pragma omp parallel for
উদ্বোধন

2
আমি কমপ্যাক্ট সংস্করণ পছন্দ করি কারণ পড়ার মতো কম কোড রয়েছে। একবার আপনি মানসিক সামঞ্জস্যতা তৈরি করলে এটি বোঝা আরও সহজ এবং বাগগুলি আরও ভালভাবে দাঁড়ায়। কোনও মানহীন পুনরাবৃত্তি ঘটলে এটি আরও বেশি স্পষ্ট করে তোলে কারণ কোডের অনেক বড় অংশ রয়েছে।
কোড বিদ্বেষক

87

কোনও ভেক্টরের মাধ্যমে পুনরাবৃত্তি করার সর্বোত্তম উপায়টি পুনরাবৃত্তির মাধ্যমে:

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

বা (উপরের সমতুল্য)

for (auto & element : vector) {
    element.doSomething ();
}

সি ++ 0 এক্স এর পূর্বে আপনাকে পুনরুক্তি টাইপের দ্বারা স্বয়ংক্রিয় প্রতিস্থাপন করতে হবে এবং বৈশ্বিক ফাংশন শুরু এবং শেষের পরিবর্তে সদস্য ফাংশন ব্যবহার করতে হবে।

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


5
অটো, ফ্রি শুরু / শেষগুলিও সি ++ 11। এবং এটিও আপনার অনেক ক্ষেত্রে ++ এর পরিবর্তে এটি ++ ব্যবহার করা উচিত।
ফরভেভার

হ্যাঁ আপনি ঠিক. বাস্তবায়ন beginএবং end, তবে, একটি ওয়ান-লাইনার।
জনবি

@ জনবি এটি একটি-ও-লাইনারের চেয়ে বেশি, কারণ এটি স্থির আকারের অ্যারেগুলির জন্যও কাজ করে। autoঅন্যদিকে বেশ কৃপণ হবে।
janchopanza

আপনার যদি ভেক্টরের প্রয়োজন হয় তবে এটি কেবল একটি ওয়ান-লাইনার।
জনবি

তবুও, প্রথম উদাহরণটি বিভ্রান্তিমূলক, যেহেতু এটি সি ++ 03 তে কাজ করতে পারে না, তবে আপনার ফ্রেসিংয়ের পরামর্শ দেয় যে এটি এটি করে।
janchopanza

35

এটি করার সঠিক উপায় হ'ল:

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    it->doSomething();
 }

যেখানে টি ভেক্টরের অভ্যন্তরে শ্রেণীর ধরণ। উদাহরণস্বরূপ যদি ক্লাসটি CActivity ছিল, কেবল টি এর পরিবর্তে CActivity লিখুন।

এই ধরণের পদ্ধতিটি প্রতিটি এসটিএলে (কেবল ভেক্টর নয়, যা কিছুটা ভাল) কাজ করবে।

আপনি যদি এখনও সূচকগুলি ব্যবহার করতে চান তবে উপায়টি হ'ল:

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}

std::vector<T>::size_typeসবসময় না size_t? আমি সর্বদা এটির জন্য ব্যবহার করি।
ভায়োলেট জিরাফ

1
@ ভায়োলেট জিরাফ আমি নিশ্চিত যে আপনি ঠিক আছেন (সত্যই যাচাই করেছেন না) তবে স্ট্যান্ড :: ভেক্টর <টি> :: সাইজ_ টাইপ ব্যবহার করা আরও ভাল অনুশীলন।
ডিজিএমআই

8

পুনরাবৃত্তকারীদের ব্যবহারের বেশ কয়েকটি শক্ত কারণ রয়েছে, যার কয়েকটি এখানে উল্লেখ করা হয়েছে:

পাত্রে স্যুইচ করা পরে আপনার কোডটি অকার্যকর করে না।

অর্থাত্, আপনি যদি একটি স্টাড :: ভেক্টর থেকে স্টাডি :: তালিকা বা স্টাডি :: সেট এ যান তবে আপনার সংযুক্ত মানটি পেতে আপনি সংখ্যাসূচক সূচকগুলি ব্যবহার করতে পারবেন না। একটি পুনরায় ব্যবহারকারীর ব্যবহার এখনও বৈধ।

অবৈধ পুনরাবৃত্তির রানটাইম ধরা

আপনি যদি নিজের লুপটির মাঝখানে আপনার ধারকটি পরিবর্তন করেন তবে পরের বার আপনি আপনার পুনরুক্তি ব্যবহার করবেন এটি একটি অবৈধ পুনরাবৃত্তি ব্যতিক্রম ছুঁড়ে ফেলবে।


1
আপনি কি আমাদের কিছু নিবন্ধ / পোস্টের দিকে নির্দেশ করতে পারেন যা উদাহরণ কোড সহ উপরের পয়েন্টগুলি ব্যাখ্যা করে? মহান হতে হবে! অথবা যদি আপনি একটি যুক্ত করতে পারেন :)
আনু

5

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

বিপরীতে, এখানে তালিকাভুক্ত অন্যান্য ফর্মগুলি forহ'ল রেঞ্জ ভিত্তিক লুপ এবং পুনরুক্তিগুলি, অনেক কম ত্রুটির প্রবণ। ভাষার শব্দার্থবিজ্ঞান এবং সংকলকটির ধরণের পরীক্ষার ব্যবস্থা আপনাকে ভুল সূচকটি ব্যবহার করে দুর্ঘটনাক্রমে কোনও অ্যারে অ্যাক্সেস করা থেকে বিরত করবে।


4

এসটিএল সহ প্রোগ্রামাররা iteratorsকনটেইনারগুলির সাহায্যে ট্র্যাভারিংয়ের জন্য ব্যবহার করে , যেহেতু পুনরাবৃত্তি একটি বিমূর্ত ধারণা, যা সমস্ত স্ট্যান্ডার্ড পাত্রে প্রয়োগ করা হয়। উদাহরণস্বরূপ, এর std::listকোনোটাই নেই operator []


3

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

অটো এবং লুপের জন্য ভেক্টর ব্যবহার করে te

vector<int> vec = {1,2,3,4,5}

for(auto itr : vec)
    cout << itr << " ";

আউটপুট:

1 2 3 4 5

আপনি সেট এবং তালিকা পুনরাবৃত্তি করতে এই পদ্ধতিটি ব্যবহার করতে পারেন। অটো ব্যবহার করে স্বয়ংক্রিয়ভাবে টেমপ্লেটে ব্যবহৃত ডেটা টাইপ সনাক্ত করে এবং আপনাকে এটি ব্যবহার করতে দেয়। সুতরাং, যদিও আমাদের কাছে একটি vectorছিল stringবা charএকই বাক্য গঠন ঠিক ঠিক কাজ করবে


1

লুপটি পুনরাবৃত্তি করার এবং এর মানগুলি মুদ্রণের সঠিক উপায়টি নিম্নরূপ:

#include<vector>

//declare the vector of type int
vector<int> v;

//insert the 5 element in the vector
for ( unsigned int i = 0; i < 5; i++){
    v.push_back(i);
}

//print those element
for (auto it = 0; it < v.end(); i++){
    std::cout << *it << std::endl;
}

1

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

for(int x: A) // for integer x in vector A
    cout<< x <<" "; 

0
 //different declaration type
    vector<int>v;  
    vector<int>v2(5,30); //size is 5 and fill up with 30
    vector<int>v3={10,20,30};
    
    //From C++11 and onwards
    for(auto itr:v2)
        cout<<"\n"<<itr;
     
     //(pre c++11)   
    for(auto itr=v3.begin(); itr !=v3.end(); itr++)
        cout<<"\n"<<*itr;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.