কেন আমি উত্পাদ কীওয়ার্ডটি ব্যবহার করব, যখন আমি কেবল একটি সাধারণ আইনিউমেবল ব্যবহার করতে পারি?


171

এই কোড দেওয়া:

IEnumerable<object> FilteredList()
{
    foreach( object item in FullList )
    {
        if( IsItemInPartialList( item ) )
            yield return item;
    }
}

কেন আমি কেবল এটিকে কোড করব না ?:

IEnumerable<object> FilteredList()
{
    var list = new List<object>(); 
    foreach( object item in FullList )
    {
        if( IsItemInPartialList( item ) )
            list.Add(item);
    }
    return list;
}

আমি কীডওয়ার্ডটি কি করে তা বুঝি yield। এটি সংকলককে একটি নির্দিষ্ট ধরণের জিনিস (একটি পুনরুক্তি) তৈরি করতে বলে। তবে কেন এটি ব্যবহার করবেন? এটি সামান্য কম কোড হওয়া ছাড়াও এটি আমার জন্য কী করে?


28
আমি বুঝতে পেরেছি এটি একটি উদাহরণ, তবে সত্যই, কোডটি এইভাবে লেখা উচিত : FullList.Where(IsItemInPartialList):)
ব্লুরাজা - ড্যানি পিফ্লুঘুফুট

উত্তর:


241

ব্যবহারটি yieldসংগ্রহকে অলস করে তোলে

ধরা যাক আপনার প্রথম প্রথম পাঁচটি আইটেম প্রয়োজন। আপনার উপায়, প্রথম পাঁচটি আইটেম পেতে আমাকে পুরো তালিকাটি লুপ করতে হবে। সহ yield, আমি কেবল প্রথম পাঁচটি আইটেমই লুপ করি


14
নোট করুন যে ব্যবহার FullList.Where(IsItemInPartialList)করা ঠিক ততটাই অলস হবে। কেবলমাত্র এটির জন্য কম সংকলক উত্পন্ন কাস্টম --- বন্দুক --- কোডের প্রয়োজন। লেখক এবং রক্ষণাবেক্ষণের সময় কম বিকাশকারী। (অবশ্যই, যে শুধু এই উদাহরণে ছিল না)
sehe

4
এটা লিনক, তাই না? আমি কল্পনা করি যে লিঙ্কগুলি প্রচ্ছদের নীচে খুব অনুরূপ কিছু করে।
রবার্ট হার্ভে

1
হ্যাঁ, লিনক yield returnযেখানে সম্ভব সেখানে বিলম্বিত কার্যকরকরণ ( ) ব্যবহার করেছেন ।
চাদ শোগগিনস

11
ভুলে যাবেন না যে ফলন ফেরতের বিবৃতি কখনই কার্যকর না করে আপনি এখনও একটি খালি সংগ্রহের ফলাফল পান যাতে নাল রেফারেন্স ব্যতিক্রম সম্পর্কে চিন্তা করার দরকার নেই। ফলন ফেরত চকোলেট ছিটিয়ে সঙ্গে দুর্দান্ত।
রেজার

127

পুনরুক্তিকারী ব্লকগুলির সুবিধা হ'ল তারা অলসভাবে কাজ করে। সুতরাং আপনি এইভাবে একটি ফিল্টারিং পদ্ধতি লিখতে পারেন:

public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
                                   Func<T, bool> predicate)
{
    foreach (var item in source)
    {
        if (predicate(item))
        {
            yield return item;
        }
    }
}

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

অন্য উদাহরণ হিসাবে, আপনি সহজেই পুনরাবৃত্তিকারী ব্লক ব্যবহার করে একটি অনন্ত স্ট্রিম তৈরি করতে পারেন । উদাহরণস্বরূপ, এলোমেলো সংখ্যার ক্রম এখানে:

public static IEnumerable<int> RandomSequence(int minInclusive, int maxExclusive)
{
    Random rng = new Random();
    while (true)
    {
        yield return rng.Next(minInclusive, maxExclusive);
    }
}

আপনি কীভাবে একটি তালিকায় অসীম ক্রম সংরক্ষণ করবেন?

আমার এডুলিনক ব্লগ সিরিজটি অবজেক্টগুলিকে লিনকিউ-এর একটি নমুনা বাস্তবায়ন দেয় যা পুনরুক্তিকারী ব্লকগুলির ভারী ব্যবহার করে। লিনিক্যু মূলত এটি হতে পারে যেখানে অলস - এবং একটি তালিকায় জিনিস রাখা সহজভাবে সেভাবে কাজ করে না।


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

5
@ সেবাস্তিয়ান নেগ্রাসজাস: এলোমেলো সংখ্যার ক্রম যুক্তিযুক্তভাবে অসীম। IEnumerable<BigInteger>উদাহরণস্বরূপ, আপনি সহজেই একটি ফিবোনাচি ক্রম উপস্থাপন করতে পারেন । আপনি foreachএটির সাথে ব্যবহার করতে পারেন তবে IEnumerable<T>গ্যারান্টি সম্পর্কে কিছুই নেই যে এটি সীমাবদ্ধ থাকবে।
জন স্কিটি

42

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

এর অর্থ হ'ল যখন আপনাকে প্রচুর প্রক্রিয়াকরণ করতে হবে এবং / অথবা প্রক্রিয়া করার জন্য আইটেমগুলির দীর্ঘ তালিকা থাকতে হয় তখন আপনি সবচেয়ে বেশি পার্থক্য দেখেন।


23

আপনি yieldতালিকায় নেই এমন আইটেমগুলি ফেরত দিতে ব্যবহার করতে পারেন। এখানে একটি সামান্য নমুনা যা বাতিল হওয়া অবধি কোনও তালিকার মাধ্যমে অসীমভাবে পুনরাবৃত্তি করতে পারে।

public IEnumerable<int> GetNextNumber()
{
    while (true)
    {
        for (int i = 0; i < 10; i++)
        {
            yield return i;
        }
    }
}

public bool Canceled { get; set; }

public void StartCounting()
{
    foreach (var number in GetNextNumber())
    {
        if (this.Canceled) break;
        Console.WriteLine(number);
    }
}

এই লিখেছেন

0
1
2
3
4
5
6
7
8
9
0
1
2
3
4

... ইত্যাদি। বাতিল হওয়া অবধি কনসোলে যান।


10
object jamesItem = null;
foreach(var item in FilteredList())
{
   if (item.Name == "James")
   {
       jamesItem = item;
       break;
   }
}
return jamesItem;

যখন উপরের কোডটি ফিল্টারলিস্ট () এবং লুপ আইটেমের মাধ্যমে লুপ করতে ব্যবহৃত হয় N নাম == "জেমস" তালিকার ২ য় আইটেমে সন্তুষ্ট হবে, পদ্ধতিটি ব্যবহার করে yield দ্বিগুণ ফলবে। এটি একটি অলস আচরণ।

তালিকার সাহায্যে পদ্ধতিটি সমস্ত এন বস্তুকে তালিকায় যুক্ত করবে এবং সম্পূর্ণ তালিকাটি কলিং পদ্ধতিতে পাস করবে।

এটি হ'ল ব্যবহারের ক্ষেত্রে যেখানে আইইনুমেবল এবং আইলিস্টের মধ্যে পার্থক্য হাইলাইট করা যায়।


7

আমি ব্যবহারের জন্য সবচেয়ে ভাল বাস্তব বিশ্বের উদাহরণটি yieldহ'ল কোনও ফিবোনাচি ক্রম গণনা করা calc

নিম্নলিখিত কোড বিবেচনা করুন:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(string.Join(", ", Fibonacci().Take(10)));
        Console.WriteLine(string.Join(", ", Fibonacci().Skip(15).Take(1)));
        Console.WriteLine(string.Join(", ", Fibonacci().Skip(10).Take(5)));
        Console.WriteLine(string.Join(", ", Fibonacci().Skip(100).Take(1)));
        Console.ReadKey();
    }

    private static IEnumerable<long> Fibonacci()
    {
        long a = 0;
        long b = 1;

        while (true)
        {
            long temp = a;
            a = b;

            yield return a;

            b = temp + b;
        }
    }
}

এটি ফিরে আসবে:

1, 1, 2, 3, 5, 8, 13, 21, 34, 55
987
89, 144, 233, 377, 610
1298777728820984005

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


5
আমি একটি ফিবোনাকির সিক্যুয়েন্স গণনায় "রিয়েল ওয়ার্ল্ড" কিছুই দেখতে পাচ্ছি না।
Nek

আমি সম্মত হই যে এটি সত্যই "বাস্তব-জগত" নয়, তবে এটি একটি দুর্দান্ত ধারণা।
কেসি

1

কেন [ফলন] ব্যবহার? এটি সামান্য কম কোড হওয়া ছাড়াও এটি আমার জন্য কী করে?

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

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

এটি সম্পাদন করতে, তালিকাকে অবশ্যই আরোহণের তারিখ অনুসারে বাছাই করতে হবে এবং তারপরে প্রথম ৫ টি নেওয়া হবে। এটি যদি ফলন ছাড়াই করা হত তবে সম্পূর্ণ হয়ে থাকে তবে শেষ দুটি তারিখটি যথাযথ ছিল কিনা তা নিশ্চিত করে তালিকাটি বাছাই করতে হবে।

যাইহোক, ফলন সহ, প্রথম 5 টি আইটেম একবার বাছাই করা বন্ধ হয়ে যায় এবং ফলাফল পাওয়া যায়। এটি প্রচুর পরিমাণে সময় সাশ্রয় করতে পারে।


0

ফলন ফেরতের বিবৃতি আপনাকে একবারে কেবলমাত্র একটি আইটেম ফেরত দিতে দেয়। আপনি একটি তালিকায় সমস্ত আইটেম সংগ্রহ করছেন এবং আবার সেই তালিকাটি ফিরিয়ে দিচ্ছেন যা একটি স্মৃতি ওভারহেড।

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