একবারে ফলন ফেরতের সাথে সমস্ত গণনা ফিরিয়ে দিন; লুপিং ছাড়া


164

কোনও কার্ডের জন্য বৈধতা ত্রুটি পেতে আমার নীচের ফাংশন রয়েছে। আমার প্রশ্নটি গেটআরআরসের সাথে সম্পর্কিত সম্পর্কিত। উভয় পদ্ধতির একই রিটার্নের টাইপ রয়েছে IEnumerable<ErrorInfo>

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    var errors = GetMoreErrors(card);
    foreach (var e in errors)
        yield return e;

    // further yield returns for more validation errors
}

এর মধ্যে সমস্ত ত্রুটি ফিরে পাওয়া কি সম্ভব? GetMoreErrors সেগুলি দিয়ে গণনা করেই ফেরানো ?

এটি সম্পর্কে ভাবনা সম্ভবত বোকা প্রশ্ন, তবে আমি নিশ্চিত করতে চাই যে আমি ভুল করছি না।


আরও ফলনের রিটার্নের প্রশ্ন আসতে দেখে আমি খুশি (এবং কৌতূহলী!) - আমি নিজে এটি বেশ বুঝতে পারি না। বোকা প্রশ্ন নয়!
জোশ জোর্দান

কী GetCardProductionValidationErrorsFor?
অ্যান্ড্রু হার

4
রিটার্নের getMoreErferences (কার্ড) এর সাথে কী ভুল ; ?
স্যাম জাফরন

10
@ স্যাম: "আরও বৈধতাজনিত ত্রুটির জন্য আরও ফলন ফেরত দেয়"
জন স্কিটে

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

উত্তর:


140

এটি অবশ্যই একটি নির্বোধ প্রশ্ন নয় এবং এটি এমন একটি জিনিস যা একটি একক আইটেমের জন্য yield!বনাম পুরো সংগ্রহের জন্য সমর্থন করে yield। (এটি লেজ পুনরাবৃত্তির ক্ষেত্রে খুব কার্যকর হতে পারে ...)

দুর্ভাগ্যক্রমে এটি সি # তে সমর্থিত নয়।

যাইহোক, যদি আপনার প্রতিটি ফেরত পাঠানোর বিভিন্ন পদ্ধতি থাকে তবে আপনি আপনার কোডটি আরও সহজ IEnumerable<ErrorInfo>করতে ব্যবহার করতে পারেন Enumerable.Concat:

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    return GetMoreErrors(card).Concat(GetOtherErrors())
                              .Concat(GetValidationErrors())
                              .Concat(AnyMoreErrors())
                              .Concat(ICantBelieveHowManyErrorsYouHave());
}

দুটি বাস্তবায়নের মধ্যে একটি খুব গুরুত্বপূর্ণ পার্থক্য রয়েছে যদিও: এটি এক সাথে সমস্ত প্রত্যাবর্তনকারীকে তত্ক্ষণাত কল করবে , যদিও এটি একবারে কেবল ফিরে আসা পুনরাবৃত্তিকে ব্যবহার করবে। আপনার বিদ্যমান কোডটি পরবর্তী ত্রুটিগুলি সম্পর্কে জিজ্ঞাসা করার GetMoreErrors()আগে এটি সমস্ত কিছু লুপ না করা অবধি অপেক্ষা করবে ।

সাধারণত এটি গুরুত্বপূর্ণ নয়, তবে কখন কী ঘটবে তা বোঝা উচিত।


3
ওয়েস ডায়ারের এই ধরণটির উল্লেখ করে একটি আকর্ষণীয় নিবন্ধ রয়েছে has ব্লগস.এমএসডিএন
জোহানেস

1
এর মাধ্যমে যাত্রীদের জন্য সংক্ষিপ্ত সংশোধন - এটি System.Linq.Enumeration.Concat <> (প্রথম, দ্বিতীয়)। আইনিউমারেশন নয়। কনক্যাট ()।
redcalx

@ দ্য লাস্টার: আপনার অর্থ কী তা আমি নিশ্চিত নই। এটি গণনার চেয়ে অবশ্যই গুনযোগ্য। আপনি আপনার মন্তব্য স্পষ্ট করতে পারেন?
জন স্কিটি

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

5
@ স্টিভেন: না এটি পদ্ধতিগুলি কল করছে - তবে আপনার ক্ষেত্রে GetOtherErrors()(ইত্যাদি) তাদের ফলাফলগুলি পিছিয়ে দিচ্ছে (যেহেতু তারা পুনরায় ব্লক ব্যবহার করে প্রয়োগ করা হচ্ছে)। একটি নতুন অ্যারে বা এরকম কিছু ফিরে আসার জন্য তাদের পরিবর্তন করার চেষ্টা করুন এবং আপনি কী বোঝাতে চাইছেন তা আপনি দেখতে পাবেন।
জন স্কিটি

26

আপনি এই জাতীয় সমস্ত ত্রুটি উত্সগুলি সেট করতে পারেন (পদ্ধতিটির নাম জোন স্কিটের উত্তর থেকে ধার নেওয়া)।

private static IEnumerable<IEnumerable<ErrorInfo>> GetErrorSources(Card card)
{
    yield return GetMoreErrors(card);
    yield return GetOtherErrors();
    yield return GetValidationErrors();
    yield return AnyMoreErrors();
    yield return ICantBelieveHowManyErrorsYouHave();
}

তারপরে আপনি একই সাথে পুনরাবৃত্তি করতে পারেন।

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    foreach (var errorSource in GetErrorSources(card))
        foreach (var error in errorSource)
            yield return error;
}

বিকল্পভাবে আপনি ত্রুটি উত্সগুলি সমতল করতে পারেন SelectMany

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    return GetErrorSources(card).SelectMany(e => e);
}

পদ্ধতিগুলি কার্যকর করার ক্ষেত্রেও GetErrorSourcesবিলম্ব হবে।


16

আমি দ্রুত yield_স্নিপেট নিয়ে এসেছি :

উত্পাদন_ স্নিপড ব্যবহার অ্যানিমেশন

এখানে স্নিপেট এক্সএমএল:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Author>John Gietzen</Author>
      <Description>yield! expansion for C#</Description>
      <Shortcut>yield_</Shortcut>
      <Title>Yield All</Title>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="true">
          <Default>items</Default>
          <ID>items</ID>
        </Literal>
        <Literal Editable="true">
          <Default>i</Default>
          <ID>i</ID>
        </Literal>
      </Declarations>
      <Code Language="CSharp"><![CDATA[foreach (var $i$ in $items$) yield return $i$$end$;]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

2
এটি প্রশ্নের উত্তর কীভাবে?
ইয়ান কেম্প

@ ইয়ান, আপনাকে এভাবে সি # তে নেস্টেড ফলন ফেরত করতে হবে। yield!এফ # এর মতো কোনও নেই ।
জন গিয়েজেন

এটি প্রশ্নের উত্তর নয়
Divyang4481

8

আপনার ফাংশনে আমি কোনও ভুল দেখছি না, আমি বলব এটি আপনার যা ইচ্ছা তা করছে।

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

আপনি যদি পরে পদ্ধতিতে পরবর্তী ফলন যোগ করেন তবে এটি গণনাতে 1 টি উপাদান যুক্ত করা চালিয়ে যাবে, যার ফলে এটি করা সম্ভব হবে ...

public IEnumerable<string> ConcatLists(params IEnumerable<string>[] lists)
{
  foreach (IEnumerable<string> list in lists)
  {
    foreach (string s in list)
    {
      yield return s;
    }
  }
}

4

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

public static class EnumearbleExtensions
{
    public static IEnumerable<T> UnWrap<T>(this IEnumerable<IEnumerable<T>> list)
    {
        foreach(var innerList in list)
        {
            foreach(T item in innerList)
            {
                yield return item;
            }
        }
    }
}

এবং আপনি এটি আপনার ক্ষেত্রে এটি ব্যবহার করতে পারেন

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    return DoGetErrors(card).UnWrap();
}

private static IEnumerable<IEnumerable<ErrorInfo>> DoGetErrors(Card card)
{
    yield return GetMoreErrors(card);

    // further yield returns for more validation errors
}

একইভাবে, আপনি চারপাশে মোড়ক ফাংশনটি সরিয়ে ফেলে DoGetErrorsকেবল UnWrapকলসাইটে যেতে পারেন move


2
সম্ভবত কোনও এক্সটেনশন পদ্ধতি সম্পর্কে ভাবেনি কারণ DoGetErrors(card).SelectMany(x => x)এটি একই রকম হয় এবং স্থগিত আচরণটি সংরক্ষণ করে। যা হুবহু অ্যাডাম তার উত্তরে পরামর্শ দিয়েছেন ।
হাইয়েস্ট্রুউ

3

হ্যাঁ একবারে সমস্ত ত্রুটি ফিরে পাওয়া সম্ভব। শুধু একটি List<T>বা ReadOnlyCollection<T>

একটি ফেরত দিয়ে IEnumerable<T>আপনি কিছু ক্রম ফিরে আসছেন। সংগ্রহটি ফেরত দেওয়ার মতো পৃষ্ঠের মতো দেখতে পাওয়া যায়, তবে বিভিন্ন পার্থক্য রয়েছে, আপনার মনে রাখা উচিত।

সংগ্রহগুলি

  • কলার নিশ্চিত হতে পারে যে সংগ্রহটি ফিরে আসার পরে সংগ্রহ এবং সমস্ত আইটেম উভয়ই উপস্থিত থাকবে। যদি প্রতি কল প্রতি সংগ্রহ তৈরি করতে হবে তবে সংগ্রহ ফিরিয়ে দেওয়া সত্যিই খারাপ ধারণা।
  • ফিরে আসার সময় বেশিরভাগ সংগ্রহগুলি পরিবর্তন করা যেতে পারে।
  • সংগ্রহটি সীমাবদ্ধ আকারের।

সিকোয়েন্স

  • গণনা করা যায় - এবং এটি আমরা নিশ্চিতভাবেই বলতে পারি এটি যথেষ্ট পরিমাণে।
  • ফিরে আসা ক্রম নিজেই সংশোধন করা যায় না।
  • প্রতিটি উপাদান অনুক্রমের মাধ্যমে চলমান অংশ হিসাবে তৈরি করা যেতে পারে (অর্থাত্ প্রত্যাবর্তন IEnumerable<T>অলস মূল্যায়নের অনুমতি দেয়, ফিরে আসে)List<T> আসে না)।
  • একটি অনুক্রম অসীম হতে পারে এবং কতগুলি উপাদান ফিরে আসবে তা সিদ্ধান্ত নিতে এটি কলারের কাছে ছেড়ে দিন।

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

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