পড়ার লুপটি শেষ করার কোন উপায়টি পছন্দসই পদ্ধতি?


13

যখন আপনাকে এমন পাঠককে পুনরাবৃত্তি করতে হবে যেখানে পড়তে হবে এমন আইটেমের সংখ্যা অজানা এবং এটি করার একমাত্র উপায় হ'ল আপনি শেষ পর্যন্ত আঘাত না করা পর্যন্ত পড়া চালিয়ে যাওয়া।

এটি আপনার অন্তহীন লুপের প্রায়শই প্রয়োজন হয়।

  1. সর্বদা trueএটি নির্দেশ করে যে ব্লকের ভিতরে কোথাও কোনও breakবা returnবক্তব্য থাকতে হবে ।

    int offset = 0;
    while(true)
    {
        Record r = Read(offset);
        if(r == null)
        {
            break;
        }
        // do work
        offset++;
    }
  2. নেই ডবল লুপ পদ্ধতির জন্য পঠিত।

    Record r = Read(0);
    for(int offset = 0; r != null; offset++)
    {
        r = Read(offset);
        if(r != null)
        {
            // do work
        }
    }
  3. লুপ করার সময় একক পঠন রয়েছে। সমস্ত ভাষা এই পদ্ধতিটিকে সমর্থন করে না

    int offset = 0;
    Record r = null;
    while((r = Read(++offset)) != null)
    {
        // do work
    }

আমি ভাবছি যে কোন পদ্ধতির মধ্যে সবচেয়ে কম পঠনযোগ্য এবং সাধারণভাবে ব্যবহৃত বাগ প্রবর্তনের সবচেয়ে কম সম্ভাবনা রয়েছে।

প্রতিবার যখন এগুলির একটি লিখতে হয় তখন আমার মনে হয় "আরও ভাল উপায় থাকতে হবে"


2
আপনি কেন একটি অফসেট বজায় রাখছেন? বেশিরভাগ স্ট্রিম পাঠক আপনাকে কেবল "পরবর্তী পড়তে" দেয় না?
রবার্ট হার্ভে

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

3
আপনি বিভ্রান্ত বলে মনে করছেন - প্রশ্নের শিরোনাম অন্তহীন লুপগুলি সম্পর্কে, তবে প্রশ্নের পাঠ্যগুলি লুপগুলি সমাপ্ত করার বিষয়ে। শাস্ত্রীয় সমাধান (কাঠামোগত প্রোগ্রামিংয়ের দিনগুলি থেকে) আপনার কাছে ডেটা থাকা অবস্থায় একটি প্রাক-পঠন, লুপ করা এবং লুপের শেষ ক্রিয়া হিসাবে আবার পড়া। এটি সহজ (বাগের প্রয়োজনীয়তা পূরণ করা), সবচেয়ে সাধারণ (যেহেতু এটি 50 বছর ধরে লেখা হয়েছে)। সর্বাধিক পঠনযোগ্য মতামতের বিষয়।
andy256

@ andy256 বিভ্রান্ত আমার জন্য প্রাক কফি শর্ত।
রিএকটিগুলার

1
আহ, সুতরাং সঠিক পদ্ধতিটি 1) কীবোর্ড এড়ানোর সময় কফি পান করুন, 2) কোডিং লুপ শুরু করুন।
andy256

উত্তর:


49

আমি এখানে একটি পদক্ষেপ নিতে হবে। আপনি কোডটির পিক বিশদটিতে মনোনিবেশ করছেন তবে বৃহত্তর ছবিটি অনুপস্থিত। আসুন আপনার উদাহরণের একটি লুপ দেখে নেওয়া যাক:

int offset = 0;
while(true)
{
    Record r = Read(offset);
    if(r == null)
    {
        break;
    }
    // do work
    offset++;
}

এই কোডটির অর্থ কী ? অর্থ "কোনও ফাইলের প্রতিটি রেকর্ডে কিছু কাজ করুন"। তবে কোডটি দেখতে এমন নয় । কোডটি দেখে মনে হচ্ছে "একটি অফসেট বজায় রাখা a একটি ফাইল খুলুন no কোনও শেষ শর্ত ছাড়াই একটি লুপ প্রবেশ করুন a রেকর্ডটি পড়ুন ull নালীর জন্য পরীক্ষা করুন।" আমরা সব কাজ করার আগে! আপনার যে প্রশ্নটি জিজ্ঞাসা করা উচিত তা হ'ল " আমি কীভাবে এই কোডটির উপস্থিতিটির শব্দার্থতত্ত্বের সাথে মেলে তুলতে পারি? " এই কোডটি হওয়া উচিত:

foreach(Record record in RecordsFromFile())
    DoWork(record);

কোডটি এর ইচ্ছার মতো পড়ে। আপনার শব্দার্থবিজ্ঞান থেকে আপনার প্রক্রিয়া পৃথক করুন । আপনার মূল কোডে আপনি পদ্ধতিটি মিশ্রণ করেন - লুপের বিবরণ - শব্দার্থবিজ্ঞানের সাথে - প্রতিটি রেকর্ডে সম্পন্ন কাজ।

এখন আমাদের বাস্তবায়ন করতে হবে RecordsFromFile()। যে বাস্তবায়নের সেরা উপায় কি? কে পাত্তা দেয়? এটি যে কোডটি দেখছে সেগুলি নয়। এটি বেসিক মেকানিজম কোড এবং এর দশটি লাইন। আপনি চান তা লিখুন। এ কেমন?

public IEnumerable<Record> RecordsFromFile()
{
    int offset = 0;
    while(true)
    {
        Record record = Read(offset);
        if (record == null) yield break;
        yield return record;
        offset += 1;
    }
}

এখন যেহেতু আমরা রেকর্ডের একটি অলস গণিত ক্রমটি হেরফের করছি যা বিভিন্ন প্রকারের পরিস্থিতি সম্ভব হয়ে উঠেছে:

foreach(Record record in RecordsFromFile().Take(10))
    DoWork(record);

foreach(Record record in RecordsFromFile().OrderBy(r=>r.LastName))
    DoWork(record);

foreach(Record record in RecordsFromFile().Where(r=>r.City == "London")
    DoWork(record);

ইত্যাদি।

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


3
+1 অবশেষে একটি বুদ্ধিমান উত্তর। আমি ঠিক তাই করব। ধন্যবাদ।
22.3 এ রিএকটিগুলার

1
"সেই প্রক্রিয়াটিকে তার নিজস্ব পদ্ধতিতে স্থানান্তরিত করার চেষ্টা করুন" - এটি অনেকটা এক্সট্রাক্ট মেথড রিফ্যাক্টরিংয়ের মতো শোনাচ্ছে না? "খণ্ডটিকে এমন পদ্ধতিতে রূপান্তর করুন যার নাম পদ্ধতির উদ্দেশ্য ব্যাখ্যা করে" "
gnat

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

1
@gnat: হুবহু! এই ক্ষেত্রে আমি যে বিবরণটি বের করতে চাই তা হ'ল নীতি বজায় রাখার মাধ্যমে ফাইলটি থেকে সমস্ত রেকর্ড পড়ার পদ্ধতি is নীতিটি হচ্ছে "প্রতি রেকর্ডে আমাদের কিছু কাজ করতে হবে"।
এরিক লিপার্ট

1
আমি দেখি. এইভাবে, এটি পড়া এবং বজায় রাখা সহজ। এই কোডটি অধ্যয়ন করে, আমি নীতি এবং প্রক্রিয়াতে আলাদাভাবে ফোকাস করতে পারি, এটি আমাকে মনোযোগ বিভাজন করতে বাধ্য করে না
gnat

19

আপনার একটি অন্তহীন লুপের দরকার নেই। আপনার কখনই সি # পঠনের দৃশ্যের প্রয়োজন হবে না। এটি আমার পছন্দসই পদ্ধতি, ধরে নিয়েই যে আপনার সত্যিকার অর্থে কোনও অফসেট বজায় রাখা দরকার:

Record r = Read(0);
offset=1;
while(r != null)
{
    // Do work
    r = Read(offset);
    offset++
}

এই পদ্ধতির সত্যটি স্বীকার করে যে পাঠকের জন্য একটি সেটআপ ধাপ রয়েছে, সুতরাং দুটি পঠন পদ্ধতির কল রয়েছে। whileশর্ত, লুপ শীর্ষে ধরো যদি রিডারে সব সময়ে কোন তথ্য নেই।


6

আচ্ছা এটি আপনার পরিস্থিতির উপর নির্ভর করে। তবে আমি যে আরও "সি # -ish" সমাধানগুলির কথা ভাবতে পারি তার মধ্যে একটি হ'ল বিল্ট-ইন আইইনুমেবল ইন্টারফেস এবং একটি ফোরচ লুপ ব্যবহার করা। আইনিমেটারের জন্য ইন্টারফেসটি কেবল মুভনেক্সটকে সত্য বা মিথ্যা দিয়ে কল করে, তাই আকারটি অজানা হতে পারে। তারপরে আপনার সমাপ্তির যুক্তিটি একবার লেখা হয় - গণনায় - এবং আপনাকে একাধিক স্পটে পুনরাবৃত্তি করতে হবে না।

এমএসডিএন আইনিউমেটর <টি> এর একটি উদাহরণ সরবরাহ করে । আইইনিউমরেটর <টি> ফেরত পেতে আপনাকে একটি আইওনামেবল <টি> তৈরি করতে হবে।


আপনি একটি কোড উদাহরণ দিতে পারেন?
প্রতিক্রিয়াশীল

ধন্যবাদ, আমি এটি করার সিদ্ধান্ত নিয়েছি। যদিও আমি মনে করি না প্রতিবার আপনার কাছে অন্তহীন লুপটি দিয়ে নতুন ক্লাস তৈরি করা প্রশ্নটি সমাধান করে।
36

হ্যাঁ, আপনি কী বলতে চাইছেন তা আমি জানি - প্রচুর ওহেড। পুনরাবৃত্তিকারীদের আসল প্রতিভা / সমস্যা হ'ল তারা অবশ্যই একই সময়ে দুটি সংগ্রহ পুনরুক্ত করতে সক্ষম হতে সক্ষম হয় a এত লোকের মাঝে আপনি যে কার্যকারিতা প্রয়োজন হবে না যাতে আপনি না পারে মাত্র মোড়কের প্রায় বস্তু উভয় IEnumerable এবং IEnumerator বাস্তবায়ন আছে। দেখার আরেকটি উপায় হ'ল আপনি যে স্টাফের পুনরুক্তি করছেন তার অন্তর্নিহিত সংগ্রহটি গ্রহণযোগ্য সি # দৃষ্টান্তটি মাথায় রেখে তৈরি করা হয়নি। এবং এটা ঠিক আছে। পুনরাবৃত্তির একটি যুক্ত বোনাস হ'ল আপনি সমান্তরাল সমস্ত লিনকিউ স্টাফ বিনামূল্যে পেতে পারেন!
জে ট্রানা

2

যখন আমার সূচনা, শর্ত এবং বৃদ্ধি ক্রিয়াকলাপগুলি আমি সি, সি ++ এবং সি # এর মতো লুপগুলির জন্য ব্যবহার করতে চাই। এটার মত:

for (int offset = 0, Record r = Read(offset); r != null; r = Read(++offset)){
    // loop here!
}

অথবা আপনি যদি মনে করেন এটি আরও পাঠযোগ্য। আমি ব্যক্তিগতভাবে প্রথমটিকে পছন্দ করি।

for (int offset = 0, Record r = Read(offset); r != null; offset++, r = Read(offset)){
    // loop here!
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.