শেষে মোন্ড সম্পর্কে খুব দরকারী মন্তব্য পরে সংযোজন
আসল উত্তর
যদিও বেশিরভাগ সমাধানগুলি কার্যকর হতে পারে, আমি মনে করি সেগুলি খুব দক্ষতার সাথে নয়। মনে করুন আপনি যদি প্রথম কয়েকটি অংশের প্রথম কয়েকটি আইটেম চান তবে। তারপরে আপনি আপনার অনুক্রমের সমস্ত (জিলিয়ন) আইটেমগুলিতে পুনরাবৃত্তি করতে চান না।
নিম্নলিখিতগুলি সর্বদা দু'বার গণনা করা হবে: একবার নেওয়ার জন্য এবং একবার এড়িয়ে যান। এটি আপনার ব্যবহারের চেয়ে আরও বেশি উপাদানের উপরে গণনা করবে না:
public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>
(this IEnumerable<TSource> source, int chunkSize)
{
while (source.Any()) // while there are elements left
{ // still something to chunk:
yield return source.Take(chunkSize); // return a chunk of chunkSize
source = source.Skip(chunkSize); // skip the returned chunk
}
}
এই ক্রমটি কতবার প্রকাশ করবে?
মনে করুন আপনি আপনার উত্সকে কিছু অংশে ভাগ করেছেন chunkSize
। আপনি কেবল প্রথম এন অংশগুলি গণনা করুন। প্রতিটি গণিত অংশ থেকে আপনি কেবল প্রথম এম উপাদানগুলি গণনা করবেন।
While(source.Any())
{
...
}
যে কোনও ব্যক্তি এনুমুরেটর পাবেন, 1 মুভনেক্সট () করুন এবং এনুমুরেটর ডিসপোজ করার পরে ফেরত মানটি প্রদান করবেন। এটি এন বার করা হবে
yield return source.Take(chunkSize);
রেফারেন্স উত্স অনুসারে এটি এমন কিছু করবে:
public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count)
{
return TakeIterator<TSource>(source, count);
}
static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
foreach (TSource element in source)
{
yield return element;
if (--count == 0) break;
}
}
আপনি আনীত ছাঙ্কের উপরে গণনা শুরু না করা পর্যন্ত এটি বেশি কিছু করে না। যদি আপনি বেশ কয়েকটি খণ্ড আনেন তবে প্রথম খণ্ডের উপরে গণনা না করার সিদ্ধান্ত নিলে ভবিষ্যদ্বাণী কার্যকর করা হয় না, কারণ আপনার ডিবাগার আপনাকে দেখাবে।
যদি আপনি প্রথম খণ্ডের প্রথম এম উপাদানগুলি নেওয়ার সিদ্ধান্ত নেন তবে ফলন ফেরত ঠিক এম বার সম্পাদন করা হয়। এর অর্থ:
- গণনা কর
- মুভনেক্সট () এবং বর্তমান এম টাইমগুলিতে কল করুন।
- গণকের নিষ্পত্তি করুন
প্রথম খণ্ডটি ফলন ফিরে আসার পরে, আমরা এই প্রথম অংশটি এড়িয়ে চলি:
source = source.Skip(chunkSize);
আবারো: আমরা কটাক্ষপাত করা করব রেফারেন্স উৎস খুঁজে পেতেskipiterator
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (count > 0 && e.MoveNext()) count--;
if (count <= 0)
{
while (e.MoveNext()) yield return e.Current;
}
}
}
আপনি দেখতে পাচ্ছেন, চুনক প্রতিটি উপাদানগুলির জন্য একবার SkipIterator
কল MoveNext()
। এটা কল না Current
।
সুতরাং প্রতি অংশটি আমরা দেখতে পাচ্ছি যে নিম্নলিখিতটি সম্পন্ন হয়েছে:
- যে কোনও (): গেটইনুমরেটর; 1 মুভনেক্সট (); বিশ্লেষককে নিষ্পত্তি করুন;
গ্রহণ করা():
- অংশের বিষয়বস্তু গণনা করা না হলে কিছুই নয়।
যদি সামগ্রীটি গণনা করা হয়: গণনা করা আইটেম প্রতি getEnumerator (), একটি মুভনেক্সট এবং একটি বর্তমান, ডিসপোজ এনুমুলেটর;
এড়িয়ে যান (): গণনা করা প্রতিটি খণ্ডের জন্য (অংশটির বিষয়বস্তু নয়): গেটইনিউমেটর (), মুভনেক্সট () অংশটি আকার দিন, বর্তমান নেই! গণনার নিষ্পত্তি করুন
আপনি যদি গণকের সাথে কী ঘটে থাকে তা যদি দেখেন তবে আপনি দেখতে পাবেন যে মুভনেেক্সট () এ প্রচুর কল রয়েছে এবং কেবলমাত্র Current
টিএসফোর্স আইটেমগুলির জন্য কল করে যা আপনি অ্যাক্সেস করার সিদ্ধান্ত নিয়েছেন।
আপনি যদি আকারের চুনসাইজের এন অংশগুলি গ্রহণ করেন, তবে মুভনেক্সটকে কল করুন ()
- যে কোনও জন্য এন সময় ()
- টেকের জন্য এখনও কোনও সময় নেই, যতক্ষণ না আপনি খণ্ডগুলি গণনা করবেন
- এড়িয়ে যান ()
যদি আপনি প্রতিটি আনীত অংশের কেবল প্রথম এম উপাদানগুলি গণনা করার সিদ্ধান্ত নেন তবে আপনাকে অবশ্যই গণনা করা অংশের প্রতি মুভনেক্সট এম বার কল করতে হবে।
সর্ব মোট
MoveNext calls: N + N*M + N*chunkSize
Current calls: N*M; (only the items you really access)
সুতরাং আপনি যদি সমস্ত খণ্ডের সমস্ত উপাদান গণনা করার সিদ্ধান্ত নেন:
MoveNext: numberOfChunks + all elements + all elements = about twice the sequence
Current: every item is accessed exactly once
মুভনেক্সট অনেক কাজ কিনা বা না, উত্স ক্রমের ধরণের উপর নির্ভর করে। তালিকাগুলি এবং অ্যারেগুলির জন্য এটি একটি সাধারণ সূচকবৃদ্ধি, সম্ভবত সীমার বাইরে পরীক্ষা করা উচিত।
তবে যদি আপনার IEnumerable ডাটাবেস ক্যোয়ারির ফলাফল হয় তবে নিশ্চিত হয়ে নিন যে ডেটাটি আপনার কম্পিউটারে সত্যই সত্যায়িত হয়েছে, অন্যথায় ডেটা বেশ কয়েকবার আনা হবে। DbContext এবং Dapper অ্যাক্সেস করার আগে স্থানীয় প্রক্রিয়াতে ডেটাটি সঠিকভাবে স্থানান্তর করবে। আপনি যদি একই ক্রমটি কয়েকবার গণনা করেন তবে এটি বেশ কয়েকবার আনা হয় না। ড্যাপার একটি বস্তু যা একটি তালিকা ফেরত দেয়, ডিবি কনটেক্সট মনে রাখে যে ডেটা ইতিমধ্যে নেওয়া হয়েছে।
আপনি খণ্ডগুলিতে আইটেমগুলি ভাগ করতে শুরু করার আগে AsEnumerable () বা ToLists () কল করা বুদ্ধিমান কিনা তা এটি আপনার সংগ্রহস্থলের উপর নির্ভর করে