সি ++ এ অপারেশন সেট করুন (বিদ্যমান মান আপডেট করুন)


21

আমার কোডটি এখানে:

 while (it!=s.end())  //here 's' is a set of stl and 'it' is iterator of set
    {   
        *it=*it-sub;    //'sub' is an int value
        it++;
    }

আমি পুনরুক্তি দ্বারা সেট মান মান আপডেট করতে পারবেন না। আমি সেটটির সমস্ত উপাদান থেকে একটি পূর্ণসংখ্যা মান 'উপ' বিয়োগ করতে চাই।

আসল সমস্যাটি কোথায় আছে কেউ আমাকে সহায়তা করতে পারে এবং আসল সমাধানটি কী হবে?

ত্রুটি বার্তাটি এখানে:

error: assignment of read-only location it.std::_Rb_tree_const_iterator<int>::operator*()’
   28 |             *it=*it-sub;
      |             ~~~^~~~~~~~


9
সেট থাকা উপাদানগুলি কেবল পঠনযোগ্য। একটি পরিবর্তন করে আপনি সেটগুলিতে অন্য আইটেমগুলি পুনঃক্রম করতে পারবেন।
rafix07

3
সমাধানটি হল পুনরুক্তিটি মুছতে এবং কী দিয়ে একটি নতুন সন্নিবেশ করানো *it - sub। দয়া করে নোট করুন যে std::set::erase()একটি নতুন whileপুনরাবৃত্তি প্রদান করে যা লুপটি সঠিকভাবে কাজ করতে আপনার ক্ষেত্রে ব্যবহার করতে হবে ।
শেফ

2
@ শেফ আপনি যখন সেটটিতে ইমেট করার সময় এটি করতে পারেন? এটি কি অন্তহীন লুপে শেষ হতে পারে না? বিশেষত যখন তাত্ক্ষণিকভাবে পুনরাবৃত্তি সংস্থার সাথে প্রাসঙ্গিক কোনও কাজ করা হয় যা পরিদর্শনকারী উপাদানগুলিকে পুনরায় দেখা হবে সেখানে রাখে?
ইউনোশ

1
ইমতিয়াজ কৌতূহলের বাইরে, যদি এই কার্যভারটি অনুসরণ করে থাকে, আপনি কি এখানে একটি মন্তব্যে এটি রিপোর্ট করতে পারেন (আমি ধরে নিই যে এটি কোনও অ্যাসাইনমেন্ট যার দ্বারা এটির কোনও খারাপ অর্থ ছাড়াই, আপনার প্রশ্নটি ঠিক আছে)? আপনি যেমন শেফ উত্তরের বিষয়ে আমার মন্তব্যে দেখতে পাচ্ছেন, আমি এটি নিয়ে শিক্ষকদের বৃহত্তর পরিকল্পনা সম্পর্কে অনুমান করছি। শুধু কৌতুহল.
Yunnosch

উত্তর:


22

একটি উপাদানের মূল মান std::setহয় constএকটি ভাল কারণে। এগুলি সংশোধন করা ক্রমের জন্য নষ্ট হতে পারে যা এ এর ​​জন্য প্রয়োজনীয় std::set

অতএব, সমাধানটি হল পুনরাবৃত্তিকে মুছে ফেলা এবং কী দিয়ে একটি নতুন সন্নিবেশ করানো *it - sub। দয়া করে নোট করুন যে std::set::erase()একটি নতুন পুনরাবৃত্তি প্রদান করে যা আপনার ক্ষেত্রে লুপটি সঠিকভাবে কাজ করার জন্য ব্যবহার করতে হবে।

#include<iostream>
#include<set>

template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
  const char *sep = "{ ";
  for (const T &value : values) { out << sep << value; sep = ", "; }
  return out << " }";
}

int main()
{
  std::set<int> test{ 11, 12, 13, 14, 15 };
  std::cout << "test: " << test << '\n';
  const int sub = 10;
  std::set<int>::iterator iter = test.begin();
  while (iter != test.end()) {
    const int value = *iter;
    iter = test.erase(iter);
    test.insert(value - sub);
  }
  std::cout << "test: " << test << '\n';
}

আউটপুট:

test: { 11, 12, 13, 14, 15 }
test: { 1, 2, 3, 4, 5 }

কলিরুতে লাইভ ডেমো


std::setএটির পুনরাবৃত্তি করার সময় পরিবর্তনগুলি সাধারণভাবে সমস্যা নয় তবে এটি সূক্ষ্ম সমস্যার কারণ হতে পারে।

সর্বাধিক গুরুত্বপূর্ণ সত্যটি হ'ল সমস্ত ব্যবহৃত পুনরাবৃত্তিকে অক্ষত রাখতে হবে বা আর ব্যবহার করা যাবে না। (এই কারণেই মুছে ফেলা উপাদানটির বর্তমান পুনরাবৃত্তিকে প্রত্যাবর্তনের মান হিসাবে নির্ধারিত std::set::erase()করা হয় যা হয় অক্ষত পুনরাবৃত্তকারী বা সেটটির সমাপ্তি))

অবশ্যই, উপাদানগুলি বর্তমান পুনরাবৃত্তির পিছনেও সন্নিবেশ করা যেতে পারে। যদিও এটি কোনও সমস্যা নয় তবে std::setএটি আমার উপরের উদাহরণটির লুপটি ভেঙে দিতে পারে।

এটি প্রদর্শনের জন্য, আমি উপরের নমুনাটি কিছুটা পরিবর্তন করেছি। দয়া করে নোট করুন যে লুপের সমাপ্তির জন্য আমি একটি অতিরিক্ত কাউন্টার যুক্ত করেছি:

#include<iostream>
#include<set>

template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
  const char *sep = "{ ";
  for (const T &value : values) { out << sep << value; sep = ", "; }
  return out << " }";
}

int main()
{
  std::set<int> test{ 11, 12, 13, 14, 15 };
  std::cout << "test: " << test << '\n';
  const int add = 10;
  std::set<int>::iterator iter = test.begin();
  int n = 7;
  while (iter != test.end()) {
    if (n-- > 0) {
      const int value = *iter;
      iter = test.erase(iter);
      test.insert(value + add);
    } else ++iter;
  }
  std::cout << "test: " << test << '\n';
}

আউটপুট:

test: { 11, 12, 13, 14, 15 }
test: { 23, 24, 25, 31, 32 }

কলিরুতে লাইভ ডেমো


1
এটা কি সম্ভব যে এটি কেবল কোনও কিছু বিয়োগের জন্য কাজ করে তবে অপারেশনটি এমন কোনও জায়গায় পুনরায় প্রবেশের কারণ হয় যেখানে এটি পরে দেখা হবে ....?
ইউনোশ

@ ইউনোশখ অসীম লুপের জন্য বিপদের পাশে, বর্তমান পুনরাবৃত্তির পিছনে পুনরাবৃত্তকারী প্রবেশ করানোর কোনও সমস্যা নেই। Iteters স্থিতিশীল std::set। সীমানা কেসটি বিবেচনা করা প্রয়োজন যে নতুন পুনরায় মুছে ফেলার পিছনে সরাসরি ratorোকানো হয়েছে। - এটি লুপ সন্নিবেশ পরে এড়ানো হবে।
শেফ

3
সি ++ 17 এ, আপনি extractনোডগুলি করতে পারেন , তাদের কীগুলি সংশোধন করতে পারেন এবং সেগুলিতে সেট করে ফিরতে পারেন। এটি আরও কার্যকর হবে, যেহেতু এটি অপ্রয়োজনীয় বরাদ্দ এড়ানো হয়।
ড্যানিয়েল ল্যাঙ্গার

আপনি কী ব্যাখ্যা করতে পারেন "এটি লুপে সন্নিবেশের পরে বাদ দেওয়া হবে"। আমি মনে করি আমি আপনার পয়েন্টটি সেখানে পাই না।
ইউনোশ

2
আর একটি বিষয় হ'ল একটি বিয়োগকের উপাদানটির মান এখনও পর্যন্ত অপ-প্রক্রিয়াজাত মানগুলির মধ্যে একটির মতো হতে পারে std::set। যেহেতু আপনার দুটি একই উপাদান থাকতে পারে না, সন্নিবেশটি কেবল std::setঅপরিবর্তিত থাকবে এবং আপনি পরে উপাদানটি হারাবেন। উদাহরণস্বরূপ ইনপুট সেটটি বিবেচনা করুন: {10, 20, 30}সাথে add = 10
কমিকসান্সএসএমএস

6

এটি কেবল অন্য সেট দিয়ে প্রতিস্থাপন করা সহজ

std::set<int> copy;

for (auto i : s)
    copy.insert(i - sub);

s.swap(copy);

5

আপনি std::setনকশার দ্বারা উপাদানগুলির পরিবর্তন করতে পারবেন না । দেখা

https://en.cppreference.com/w/cpp/container/set/begin

যেহেতু পুনরাবৃত্তকারী এবং কনস্টেটেরেটর উভয়ই ধ্রুব পুনরুক্তি হয় (এবং প্রকৃতপক্ষে একই ধরণের হতে পারে), এই সদস্য ফাংশনগুলির দ্বারা ফেরত পাঠানো কোনও পুনরুক্তকারকের মাধ্যমে ধারকটির উপাদানগুলিকে পরিবর্তন করা সম্ভব নয়।

সেটটি বাছাই করার কারণে । আপনি যদি একটি সাজানো সংগ্রহে উপাদানকে পরিবর্তন করেন তবে সংগ্রহটি অবশ্যই আবার বাছাই করতে হবে যা অবশ্যই সম্ভব, তবে সি ++ উপায় নয়।

আপনার বিকল্পগুলি হ'ল:

  1. অন্য ধরণের সংগ্রহ (আনসোর্টড) ব্যবহার করুন।
  2. একটি নতুন সেট তৈরি করুন এবং এটি সংশোধিত উপাদানগুলিতে পূরণ করুন।
  3. এর থেকে কোনও উপাদান সরান std::set, এটিকে সংশোধন করুন, তারপরে আবার sertোকান। (আপনি যদি প্রতিটি উপাদানকে সংশোধন করতে চান তবে এটি ভাল ধারণা নয়)

4

একজন std::setসাধারণত একটি স্ব-মিট STL মধ্যে বাইনারি ট্রি হিসাবে প্রয়োগ করা হয়। *itগাছটি অর্ডার করতে ব্যবহৃত উপাদানটির মান is যদি এটি সংশোধন করা সম্ভব হয়, অর্ডারটি অবৈধ হয়ে যাবে তাই এটি করা সম্ভব নয়।

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

প্রদত্ত লুপের জন্য এটি একটিতে করা সম্ভব sub > 0S.erase(pos)অবস্থানে পুনরাবৃত্তি অপসারণ posএবং নিম্নলিখিত অবস্থানটি ফেরত দেয়। যদি sub > 0, আপনি যে আপডেট করা মানটি সন্নিবেশ করান তা গাছের নতুন পুনরাবৃত্তির মানটির আগে আসবে তবে যদি sub <= 0, তবে আপডেট হওয়া মানটি গাছের নতুন পুনরায় বিবর্তকের মানের পরে আসবে এবং তাই আপনি শেষ করতে পারবেন অগণিত চক্র.

for (auto itr = S.begin(); itr != S.end(); )
{
    int val = *itr;
    itr = S.erase(itr);
    S.insert(val - sub);
}

এটি একটি ভাল উপায় ... আমি মনে করি এটি করার একমাত্র উপায় delete মুছুন এবং আবার সন্নিবেশ করুন।
ইমতিয়াজ মেহেদী

3

ত্রুটিটি বেশ সমস্যার সমাধান করে

std::setধারক সদস্যরা হলেনconst । তাদের পরিবর্তন করা তাদের নিজ নিজ অর্ডারটিকে অবৈধ করে তোলে।

মধ্যে উপাদান পরিবর্তন করার জন্য std::set , আপনাকে আইটেমটি মুছতে হবে এবং পরিবর্তন করার পরে এটি পুনরায় োকাতে হবে।

বিকল্পভাবে, আপনি ব্যবহার করতে পারেন std::map এই দৃশ্যটি কাটিয়ে উঠতে ।

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