ফিল্টারিং ফোরচ লুপগুলি এমন কোনও স্থানে যেখানে শর্তের তুলনায় গার্ড ক্লজ থাকে


24

আমি কিছু প্রোগ্রামার এটি ব্যবহার করতে দেখেছি:

foreach (var item in items)
{
    if (item.Field != null)
        continue;

    if (item.State != ItemStates.Deleted)
        continue;

    // code
}

পরিবর্তে যেখানে আমি সাধারণত ব্যবহার করব:

foreach (var item in items.Where(i => i.Field != null && i.State != ItemStates.Deleted))
{
    // code
}

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


3
নিয়মিত তালিকার জন্য এটি মাইক্রো অপ্টিমাইজেশনের মতো শোনাচ্ছে।
সর্বশেষ

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

2
অবশ্যই অবিরত দ্রুত হবে। লিনক ব্যবহার করা হচ্ছে। আপনি অতিরিক্ত পুনরুক্তি তৈরি করতে পারেন।
সর্বনাশ

1
@zgnilec - ভাল তত্ত্ব। আপনি কেন এমন ভাবছেন তা ব্যাখ্যা করে একটি উত্তর পোস্ট করার জন্য যত্নশীল ? উভয় উত্তর যা বর্তমানে বিদ্যমান তা বিপরীত বলে।
ববসন

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

উত্তর:


64

আমি এটিকে কমান্ড / ক্যোয়ারী বিভাজন ব্যবহারের উপযুক্ত জায়গা হিসাবে বিবেচনা করব । উদাহরণ স্বরূপ:

// query
var validItems = items.Where(i => i.Field != null && i.State != ItemStates.Deleted);
// command
foreach (var item in validItems) {
    // do stuff
}

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

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

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


1
কেন একটি অত্যন্ত বড় ডেটা সেট একটি পার্থক্য করতে হবে? ল্যাম্বডাসের সংক্ষিপ্ত ব্যয়টি কেবল শেষ পর্যন্ত বাড়িয়ে দেবে বলেই?
ব্লুরাজা - ড্যানি প্লেফুঘিফ্ট

1
@ ব্লুরাজা-ড্যানিপ্লুঘুফুট: হ্যাঁ আপনি ঠিক বলেছেন, এই উদাহরণটিতে মূল কোডের বাইরে কোনও অতিরিক্ত অ্যালগরিদমিক জটিলতা জড়িত না। আমি কথাটি সরিয়ে ফেলেছি।
ক্রিশ্চান হাইটার

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

1
@ ডেভিডপ্যাকার নং। কেবল লুপ IEnumerableদ্বারা চালিত foreach
বেনিয়ামিন হজসন

2
@ ডেভিডপ্যাকার: এটি ঠিক তাই করে; বেশিরভাগ লিনিক টু অবজেক্টস পদ্ধতি পুনরুক্তিকারী ব্লক ব্যবহার করে প্রয়োগ করা হয়। উপরের উদাহরণ কোডটি সংগ্রহের মাধ্যমে ঠিক একবারে পুনরাবৃত্তি হবে, Whereল্যাম্বডা এবং লুপের বডি (যদি ল্যাম্বদা সত্য হয়ে যায়) প্রতি উপাদান হিসাবে একবার চালায়।
খ্রিস্টান হাইটার

7

অবশ্যই পারফরম্যান্সের মধ্যে পার্থক্য রয়েছে, .Where()প্রতিটি আইটেমের জন্য ডেলিগেট কল করা ফলাফল। তবে আমি পারফরম্যান্স নিয়ে মোটেই চিন্তিত হব না:

  • কোনও প্রতিনিধিকে আহ্বান জানাতে ব্যবহৃত ক্লকচক্রগুলি কোডটির বাকী কোড দ্বারা ব্যবহৃত ক্লকচক্রের তুলনায় নগন্য যা এই সংগ্রহটি পুনরুক্ত করে এবং শর্তগুলি পরীক্ষা করে।

  • কোনও প্রতিনিধিকে আহ্বান করার পারফরম্যান্স পেনাল্টিটি কয়েকটি ঘড়ির চক্রের ক্রম এবং ভাগ্যক্রমে, আমরা অনেক দিন অতিবাহিত করেছি যখন আমাদের ব্যক্তিগত ঘড়ির চক্র সম্পর্কে চিন্তিত হয়েছিল।

যদি কোনও কারণে কর্মক্ষেত্রটি আপনার জন্য ঘড়ির চক্র স্তরে সত্যিই গুরুত্বপূর্ণ হয়, তবে তার List<Item>পরিবর্তে ব্যবহার করুন IList<Item>, যাতে সংকলক ভার্চুয়াল কলগুলির পরিবর্তে সরাসরি (এবং ইনলাইনেবল) কলগুলি ব্যবহার করতে পারে, এবং যাতে পুনরুক্তিকারী List<T>, যা আসলে ক struct, বক্স করা হবে না। তবে তা আসলেই ছোট ছোট জিনিস।

একটি ডাটাবেস ক্যোয়ারী একটি পৃথক পরিস্থিতি, কারণ সেখানে (কমপক্ষে তত্ত্বের ক্ষেত্রে) ফিল্টারটি আরডিবিএমএসে প্রেরণের সম্ভাবনা রয়েছে, এইভাবে পারফরম্যান্সের ব্যাপক উন্নতি ঘটে: কেবলমাত্র সারি সারিগুলি আপনার প্রোগ্রামে আরডিবিএমএস থেকে ট্রিপ তৈরি করবে। তবে তার জন্য আমি মনে করি আপনাকে লিনক ব্যবহার করতে হবে, আমি মনে করি না যে এই অভিব্যক্তিটি আরডিবিএমএস-তে যেমন পাঠানো যেতে পারে।

আপনি if(x) continue;এই কোডটি ডিবাগ করার মুহূর্তের সুবিধাগুলি সত্যিই দেখতে পাবেন : একক পদক্ষেপ if()এবং continueগুলি খুব ভালভাবে কাজ করে; ফিল্টারিং প্রতিনিধি একক পদক্ষেপ একটি ব্যথা হয়।


এটি তখনই যখন কোনও সমস্যা হয় এবং আপনি সমস্ত আইটেমটি দেখতে এবং ডিবাগারটি দেখতে চান যা কোনটির ক্ষেত্র! = নাল, এবং কোনটি স্টেট রয়েছে! = নাল; এই ভবিষ্যদ্বাণী দিয়ে অসম্ভব কঠিন হতে পারে ... যেখানে।
gnasher729

ডিবাগিংয়ের সাথে ভাল পয়েন্ট। ভিজ্যুয়াল স্টুডিওতে এমন কোনও জায়গায় পদক্ষেপ নেওয়া খারাপ নয়, তবে আপনি পুনরায় কম্পাইল না করে ডিবাগ করার সময় ল্যাম্বডা এক্সপ্রেশনগুলি আবার লিখতে পারবেন না এবং এটি ব্যবহারের সময় আপনি এড়াতে পারবেন if(x) continue;
পাপ্রিক

কড়া কথা বলতে গেলে .Whereকেবল একবারই অনুরোধ করা হয়। প্রতিটি পুনরাবৃত্তির জন্য যা MoveNextCurrent
চাওয়া

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