হাতে লিখিত লুপগুলিতে অ্যালগরিদম পছন্দ করবেন?


10

নিচের কোনটি আপনার কাছে বেশি পাঠযোগ্য? হাতে লেখা লুপ:

for (std::vector<Foo>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
    bar.process(*it);
}

বা অ্যালগরিদম অনুরোধ:

#include <algorithm>
#include <functional>

std::for_each(vec.begin(), vec.end(),
              std::bind1st(std::mem_fun_ref(&Bar::process), bar));

আমি ভাবছি std::for_eachসত্যিই এটির মূল্য আছে কিনা, এমন একটি সাধারণ উদাহরণ হিসাবে ইতিমধ্যে এতগুলি কোডের প্রয়োজন।

এই বিষয়ে আপনার মতামত কি?


2
সি ++ এর জন্য উত্তরটি বেশ সুস্পষ্ট। তবে অন্যান্য ভাষায়, উভয়ই সমান (উদাহরণস্বরূপ পাইথন: map(bar.process, vec)যদিও পার্শ্ব প্রতিক্রিয়াগুলির জন্য মানচিত্রটি নিরুৎসাহিত করা হয় এবং মানচিত্রের উপরে তালিকা বোঝার / জেনারেটরের এক্সপ্রেশন প্রস্তাবিত হয়)।

5
এবং তারপরেও রয়েছে BOOST_FOREACH...
বেনজমিন ব্যানিয়ের

তাহলে, কার্যকর এসটিএলে থাকা আইটেমটি আপনাকে বোঝায় না? stackoverflow.com/questions/135129/…
চাকরী

উত্তর:


18

ল্যাম্বডাস চালু হওয়ার একটি কারণ রয়েছে এবং এটি স্ট্যান্ডার্ড কমিটিকে স্বীকৃতি দেয় যে দ্বিতীয় ফর্মটি সফল হয়। আপনি সি ++ 0 এক্স এবং ল্যাম্বদা সমর্থন না পাওয়া পর্যন্ত প্রথম ফর্মটি ব্যবহার করুন।


2
দ্বিতীয় যুক্তিকে ন্যায়সঙ্গত করতে একই যুক্তি ব্যবহার করা যেতে পারে: স্ট্যান্ডার্ড কমিটি স্বীকৃতি দিয়েছে যে এটি এত উন্নত যে তারা ল্যাম্বডাসকে আরও উন্নত করার জন্য প্রবর্তন করেছিল। :-p (তবুও +1)
কনরাড

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

দ্রষ্টব্য: দুটি বড় অভিযোগের কারণে ল্যাম্বদা সমর্থন যুক্ত করা হয়েছিল। 1) স্ট্যান্ডার্ড বয়লারপ্লিটটি ফান্টাক্টরগুলিতে পরামিতিগুলি পাস করার জন্য প্রয়োজনীয়। 2) কল পয়েন্টে কোড না থাকা। আপনি কেবল কোনও পদ্ধতিতে কল করছেন বলে আপনার কোড এগুলির কোনওটিকেই সন্তুষ্ট করে না। সুতরাং 1) পরামিতিগুলি পাস করার জন্য কোনও অতিরিক্ত কোড 2) কোডটি ইতিমধ্যে কল পয়েন্টে নেই তাই ল্যাম্বড্ড কোড রক্ষণাবেক্ষণের উন্নতি করতে পারে না। সুতরাং হ্যাঁ ল্যাম্বদা একটি দুর্দান্ত সংযোজন। এটি তাদের পক্ষে ভাল যুক্তি নয়।
মার্টিন ইয়র্ক

9

আপনি যা করতে চান তা সর্বদা বর্ণনা করে এমন বৈকল্পিকটি ব্যবহার করুন । এটাই

প্রতিটি উপাদান xজন্য vec, না bar.process(x)

এখন, উদাহরণগুলি পরীক্ষা করা যাক:

std::for_each(vec.begin(), vec.end(),
              std::bind1st(std::mem_fun_ref(&Bar::process), bar));

আমরা একটি আছে for_eachকিনা, সে - yippeh । আমাদের যে [begin; end)পরিসরটি পরিচালনা করতে চাই তা আমাদের রয়েছে।

নীতিগতভাবে, অ্যালগরিদম হ'ল লিখিত বাস্তবায়নের চেয়ে অনেক বেশি স্পষ্ট এবং এভাবে পছন্দনীয় ছিল। তবে কি ... বাইন্ডার? Memfun? মূলত সি ++ ইন্টার্না কিভাবে সদস্য ফাংশন ধরে রাখবেন? আমার কাজের জন্য, আমি তাদের সম্পর্কে চিন্তা করি না ! আমি এই ভার্বোস, ক্রাইপি সিনট্যাক্সেও ভুগতে চাই না।

এখন অন্য সম্ভাবনা:

for (std::vector<Foo>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
    bar.process(*it);
}

মঞ্জুর, এটি স্বীকৃতি দেওয়ার জন্য একটি সাধারণ প্যাটার্ন, তবে ... পুনরাবৃত্তকারী তৈরি করা, লুপিং, ইনক্রিমেন্টিং, ডিরেফারেন্সিং। এগুলিও আমার কাজটি সম্পাদন করার জন্য আমার যত্ন নেই things

স্বীকার করা যায়, এটি প্রথম সমাধানের চেয়ে অপেক্ষাকৃত ভাল দেখায় (কমপক্ষে, লুপের দেহটি নমনীয় এবং বেশ স্পষ্ট) তবে তবুও এটি আসলে এত দুর্দান্ত নয়। আমাদের যদি আরও ভাল সম্ভাবনা না থাকে তবে আমরা এটি ব্যবহার করব, তবে আমাদের সম্ভবত ...

একটি ভাল উপায়?

এখন ফিরে for_each। এটি করা অপারেশনটিতে আক্ষরিকভাবে বলা for_each এবং নমনীয় হওয়া কি দুর্দান্ত হবে না? ভাগ্যক্রমে, যেহেতু সি ++ 0 এক্স ল্যাম্বডাস, আমরা আছি

for_each(v.begin(), v.end(), [&](const Foo& x) { bar.process(x); })

এখন যেহেতু আমরা অনেকগুলি সম্পর্কিত পরিস্থিতিতে একটি বিমূর্ত, জেনেরিক সমাধান খুঁজে পেয়েছি, এটি লক্ষণীয় যে এই বিশেষ ক্ষেত্রে একটি পরম # 1 প্রিয় রয়েছে :

foreach(const Foo& x, vec) bar.process(x);

এটি এর চেয়ে বেশি পরিষ্কার হতে পারে না। ধন্যবাদ, সি ++ 0 এক্স অন্তর্নির্মিত অনুরূপ সিনট্যাক্সের মত !


2
বলেছে "অনুরূপ সিনট্যাক্স" হচ্ছে for (const Foo& x : vec) bar.process(x);, বা const auto&যদি আপনার পছন্দ হয় তবে ব্যবহার করছেন ।
জন পূর্ব

const auto&সম্ভব? জানতেন না - দুর্দান্ত তথ্য!
দারিও

8

কারণ এটি এত অপঠনযোগ্য?

for (unsigned int i=0;i<vec.size();i++) {
{
    bar.process(vec[i]);
}

4
দুঃখিত, তবে কিছু কারণে এটি "সেন্সরড" বলে যেখানে আমি বিশ্বাস করি যে আপনার কোডটি হওয়া উচিত।
মতিন উলহাক

6
আপনার কোডটি একটি সংকলককে সতর্কতা দেয়, কারণ একটির intসাথে তুলনা size_tকরা বিপজ্জনক। এছাড়াও, ইনডেক্সিং প্রতিটি পাত্রের সাথে কাজ করে না, উদাহরণস্বরূপ std::set
ফ্রেডওভারফ্লো

2
এই কোডটি কেবলমাত্র একটি ইনডেক্সিং অপারেটরযুক্ত ধারকগুলির জন্য কাজ করবে, যার মধ্যে কয়েকটি কম রয়েছে। এটি অ্যালগরিদমকে নির্লজ্জভাবে সংযুক্ত করে - যদি কোনও মানচিত্র <> আরও ভাল মানায় তবে কী হবে? লুপ এবং for_each এর জন্য আসলটি প্রভাবিত হবে না।
জেবিআরউইলকিনসন

2
এবং আপনি কতবার কোনও ভেক্টরের জন্য কোড ডিজাইন করেন এবং তারপরে কোনও মানচিত্রের জন্য এটি অদলবদল করার সিদ্ধান্ত নেন? যেন এর জন্য ডিজাইনিং করা ছিল ভাষাগুলির অগ্রাধিকার।
মার্টিন বেকেট

2
সূচকের মাধ্যমে সংগ্রহগুলি ওভারেটিং নিরুত্সাহিত করা হয় কারণ কিছু সংগ্রহের সূচীকরণের ক্ষেত্রে খারাপ পারফরম্যান্স থাকে, অন্যদিকে পুনরাবৃত্তিকারী ব্যবহার করার সময় সমস্ত সংগ্রহগুলি ভাল আচরণ করে।
slaphappy

3

সাধারণভাবে, প্রথম ফর্মটি যে কেউ জানেন যে একটি লুপ কী তা জানেন না, তাদের পটভূমি কোনও ব্যাপার নয়।

সাধারণভাবে, দ্বিতীয়টি মোটেও পঠনযোগ্য নয়: ফোর_এচ কী করছে তা নির্ধারণ করার পক্ষে যথেষ্ট সহজ, তবে আপনি যদি কখনও দেখেন নি তবে std::bind1st(std::mem_fun_refআমি বুঝতে পারি যে এটি বুঝতে অসুবিধা হয়।


2

আসলে, এমনকি সি ++ 0 এক্স থাকা সত্ত্বেও আমি নিশ্চিত না যে for_eachখুব বেশি ভালবাসা পাবে।

for(Foo& foo: vec) { bar.process(foo); }

উপায় আরও পাঠযোগ্য।

অ্যালগরিদমগুলি সম্পর্কে (সি ++ এ) যে জিনিসটি আমি অপছন্দ করি তা হ'ল এটি পুনরাবৃত্তকারীদের উপর যুক্তিযুক্ত, খুব ভার্জোজিক স্টেটমেন্ট দেয়।


2

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

// custom functor
class Bar
{    public: void operator()(Foo& value) { /* STUFF */ }
};


std::for_each(vec.begin(), vec.end(), Bar());

এখানে কোডটি বেশ পঠনযোগ্য।


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

দেখুন এখানে কেন আমি মনে করি এই কোড খারাপ জন্য।
এসবিআই

1

আমি পরেরটি পছন্দ করি কারণ এটি পরিষ্কার এবং পরিষ্কার। এটি আসলে অন্য অনেক ভাষার অংশ তবে সি ++ এ এটি লাইব্রেরির অংশ। এটা আসলে বিষয় নয়।


0

এখন এই সমস্যাটি আসলে সি ++ এর সাথে নির্দিষ্ট নয়, আমি দাবি করব।

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

একটি সাধারণ ব্যবহার যা আমি অন্যান্য ভাষায় দেখতে পাই তা হ'ল:

someCollection.forEach(someUnaryFunctor);

এর সুবিধাটি হ'ল, আপনার someCollectionবাস্তবের প্রয়োগ কীভাবে করা হয় বা কী someUnaryFunctorহয় তা আপনার জানা দরকার। আপনার যা যা জানা দরকার তা হ'ল, এর forEachপদ্ধতিটি সংগ্রহের সমস্ত উপাদানকে পুনরাবৃত্তি করবে এবং তাদের প্রদত্ত ফাংশনে স্থান দেবে।

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

এছাড়াও, আপনার মনে রাখা উচিত, কার্যকরী পদ্ধতির ধীর গতি কম কারণ আপনার প্রচুর কল রয়েছে, যা একটি নির্দিষ্ট মূল্যে আসে, আপনার কোনও লুপ নেই।


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

@ এন্ড্রেস এফ: সুতরাং এটি আরও পরিষ্কার দেখাচ্ছে? std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun_ref(&Bar::process), bar));এবং এটি রানটাইমের সময় ধীরে ধীরে বা সংকলনের সময় (যদি আপনি ভাগ্যবান হন)। ফাংশন কলগুলির সাথে ফ্লো কন্ট্রোল স্ট্রাকচারের পরিবর্তে কোড কেন আরও ভাল হয় তা আমি দেখছি না। এখানে উপস্থাপিত যে কোনও বিকল্প সম্পর্কে আরও পঠনযোগ্য।
back2dos

0

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

যেখানে একটি অ্যালগরিদম রয়েছে যা আপনি যা চান তা আরও দৃly়তার সাথে করে তবে হ্যাঁ আপনার হাতে লেখা লুপগুলির চেয়ে অ্যালগোরিদম পছন্দ করা উচিত। এখানে সুস্পষ্ট উদাহরণ বাছাই করা হয় sortবা stable_sortবা অনুসন্ধানের lower_bound, upper_boundবা equal_range, কিন্তু তাদের অধিকাংশই কিছু অবস্থা যা তারা একটি হাত কোডেড লুপ উপর ব্যবহার করা বাঞ্ছনীয় আছে।


0

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

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