এন আকারের ছোট তালিকায় একটি তালিকা বিভক্ত করুন


209

আমি একটি তালিকা ছোট ছোট তালিকার একটি সিরিজে বিভক্ত করার চেষ্টা করছি।

আমার সমস্যা: তালিকাগুলি বিভক্ত করার জন্য আমার কাজগুলি সেগুলি সঠিক আকারের তালিকায় বিভক্ত করে না। এটি তাদের 30 টি আকারের তালিকায় বিভক্ত করা উচিত তবে পরিবর্তে এটি তাদের 114 আকারের তালিকায় বিভক্ত করে তোলে?

আমি কীভাবে আমার ফাংশনটিকে 30 টি বা তারও কম আকারের তালিকাগুলির X সংখ্যায় একটি তালিকা বিভক্ত করতে পারি ?

public static List<List<float[]>> splitList(List <float[]> locations, int nSize=30) 
{       
    List<List<float[]>> list = new List<List<float[]>>();

    for (int i=(int)(Math.Ceiling((decimal)(locations.Count/nSize))); i>=0; i--) {
        List <float[]> subLocat = new List <float[]>(locations); 

        if (subLocat.Count >= ((i*nSize)+nSize))
            subLocat.RemoveRange(i*nSize, nSize);
        else subLocat.RemoveRange(i*nSize, subLocat.Count-(i*nSize));

        Debug.Log ("Index: "+i.ToString()+", Size: "+subLocat.Count.ToString());
        list.Add (subLocat);
    }

    return list;
}

যদি আমি 144 আকারের তালিকায় ফাংশনটি ব্যবহার করি তবে আউটপুটটি হ'ল:

সূচক: 4, আকার: 120
সূচক: 3, আকার: 114
সূচক: 2, আকার: 114
সূচক: 1, আকার: 114
সূচক: 0, আকার: 114


1
যদি একটি লিনকিউ সমাধানটি গ্রহণযোগ্য হয় তবে এই প্রশ্নটি কিছুটা সহায়ক হতে পারে

বিশেষত পূর্ববর্তী প্রশ্নে স্যাম জাফরনের উত্তর। এবং যদি না এটি কোনও স্কুল বরাদ্দের জন্য হয় তবে আমি কেবল তার কোডটি ব্যবহার করব এবং থামাব।
jcolebrand

উত্তর:


268
public static List<List<float[]>> SplitList(List<float[]> locations, int nSize=30)  
{        
    var list = new List<List<float[]>>(); 

    for (int i = 0; i < locations.Count; i += nSize) 
    { 
        list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i))); 
    } 

    return list; 
} 

জেনেরিক সংস্করণ:

public static IEnumerable<List<T>> SplitList<T>(List<T> locations, int nSize=30)  
{        
    for (int i = 0; i < locations.Count; i += nSize) 
    { 
        yield return locations.GetRange(i, Math.Min(nSize, locations.Count - i)); 
    }  
} 

সুতরাং যদি আমার তালিকার দৈর্ঘ্য জিলিয়ন থাকে এবং আমি ছোট তালিকাগুলির দৈর্ঘ্য 30 এ বিভক্ত করতে চাই এবং প্রতিটি ছোট তালিকা থেকে আমি কেবল (1) নিতে চাই, তবে আমি এখনও 30 টি আইটেমের তালিকা তৈরি করি যার মধ্যে আমি 29 টি আইটেম ফেলে দিই। এটি আরও স্মার্ট করা যায়!
হ্যারাল্ড কপুলস

এটি কি আসলে কাজ করে? আপনি কি এন সাইজের এন সাইজ রেঞ্জ পেয়ে যাচ্ছেন তা প্রথম বিভাজনে ব্যর্থ হবে না? উদাহরণস্বরূপ যদি এন সাইজ 3 হয় এবং আমার অ্যারের আকার 5 হয় তবে প্রথম সূচক পরিসীমাটি ফিরে আসেGetRange(3, 3)
ম্যাথু পিগ্রাম

2
@ ম্যাথিউপিগ্রাম পরীক্ষা করেছে এবং এটি কাজ করছে। ম্যাথ.মিন ন্যূনতম মানটি গ্রহণ করে তাই শেষ অংশটি যদি এন সাইজের (2 <3) এর চেয়ে কম হয় তবে এটি অবশিষ্ট আইটেমগুলির সাথে একটি তালিকা তৈরি করে।
Phet01

1
@ হারাল্ডকপলস ওপিকে কেবল নির্বাচনের তালিকাগুলি বাছাইয়ের জন্য জিজ্ঞাসা করেননি
Phet01

@ ম্যাথেজপিগ্রাম প্রথম পুনরাবৃত্তি - গেটরেঞ্জ (0,3), দ্বিতীয় পুনরাবৃত্তি - গেটরেঞ্জ (3,2)
-টিএম

381

আমি উত্স তালিকাটি নির্দিষ্ট তালিকা আকারের দ্বারা সাব-তালিকাগুলিতে কাটাতে এই এক্সটেনশন পদ্ধতিটি ব্যবহার করার পরামর্শ দেব:

/// <summary>
/// Helper methods for the lists.
/// </summary>
public static class ListExtensions
{
    public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) 
    {
        return source
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkSize)
            .Select(x => x.Select(v => v.Value).ToList())
            .ToList();
    }
}

উদাহরণস্বরূপ, আপনি যদি প্রতি অংশে 5 টি আইটেম দ্বারা 18 টি আইটেমের তালিকা ছাঁটাই করেন তবে এটি আপনাকে নীচের আইটেমগুলির সাথে 4 টি উপ-তালিকার তালিকা দেয়: 5-5-5-5।


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

4
অবশ্যই, @ নিক আমি সাধারণভাবে কিছু করার আগে চিন্তা করার পরামর্শ দেব। লিনকিউ-এর সাথে অংশ নষ্ট করা প্রায়শই হাজারবার পুনরাবৃত্তি করা উচিত নয়। সাধারণত আপনাকে ব্যাচ দ্বারা এবং / বা সমান্তরালে আইটেম ব্যাচের প্রসেসিংয়ের জন্য তালিকাগুলি ছিন্ন করতে হবে।
দিমিত্রি পাভলভ

6
আমি মনে করি না স্মৃতি এবং অভিনয় এখানে বড় সমস্যা হওয়া উচিত। আমার কাছে প্রায় 200000 রেকর্ডের সাথে একটি তালিকা প্রায় 3000 টির সাথে ছোট তালিকায় বিভক্ত করার প্রয়োজন হয়েছিল যা আমাকে এই থ্রেডে নিয়ে এসেছিল এবং আমি উভয় পদ্ধতি পরীক্ষা করে দেখেছি যে চলমান সময় প্রায় একই রকম is এর পরে আমি সেই তালিকাকে 3 টি রেকর্ডের সাথে তালিকায় বিভক্ত করার পরীক্ষা করেছি এবং এখনও কর্মক্ষমতা ঠিক আছে। আমি মনে করি সেরজ-টিএম এর সমাধানটি আরও সহজবোধ্য এবং যদিও এটির আরও ভাল রক্ষণাবেক্ষণ রয়েছে।
নিরব Sojourner 21

2
মনে রাখবেন যে এটিগুলি ছেড়ে দেওয়া ভাল ToList(), এবং অলস মূল্যায়নটিকে যাদু করতে দিন।
ইয়ার হালবারস্টেট

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

37

কেমন:

while(locations.Any())
{    
    list.Add(locations.Take(nSize).ToList());
    locations= locations.Skip(nSize).ToList();
}

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

2
হ্যাঁ প্রতিটি লুপে নতুন তালিকা তৈরি করা হয়। হ্যাঁ এটি স্মৃতি গ্রাস করে। তবে আপনার যদি মেমরির সমস্যা হয় তবে এই তালিকার উদাহরণগুলি পরবর্তী লুপে সংগ্রহ করার জন্য প্রস্তুত হওয়ায় এটি অনুকূলিত করার জায়গা নয়। আপনি এড়িয়ে গিয়ে মেমরির জন্য পারফরম্যান্স ট্রেড করতে পারেন ToListতবে আমি এটিকে অপ্টিমাইজ করার চেষ্টা করে বিরক্ত করব না - এটি এত তুচ্ছ এবং অসম্ভব একটি বাধা। এই বাস্তবায়নটি থেকে প্রধান লাভটি হ'ল তার তুচ্ছতা এটি বোঝা সহজ। আপনি যদি চান তবে আপনি গৃহীত উত্তরটি ব্যবহার করতে পারেন এটি সেই তালিকা তৈরি করে না তবে এটি আরও জটিল।
রাফাল

2
.Skip(n)nপ্রতিবার যখন এটি বলা হয় তখন উপাদানগুলির উপর পুনরাবৃত্তি হয় , যখন এটি ঠিক থাকতে পারে, পারফরম্যান্স-সমালোচনামূলক কোডের জন্য বিবেচনা করা গুরুত্বপূর্ণ। stackoverflow.com/questions/20002975/...
Chakrava

@ চক্রভ নিশ্চিত, আমার সমাধানটি পারফরম্যান্স ক্রিটিকাল কোডে ব্যবহার করা যাবেনা, তবুও আমার অভিজ্ঞতায় আপনি প্রথমে ওয়ার্কিং কোড লিখবেন এবং তারপরে পারফরম্যান্সটি কী সমালোচনামূলক তা নির্ধারণ করুন এবং এটি খুব কমই যেখানে আমার লিনিক অবজেক্ট অপারেশনগুলিতে 50 টি অবজেক্ট বলে। এটি কেস দ্বারা কেস মূল্যায়ন করা উচিত।
রাফাল 25'16

@ রাফাল আমি সম্মত, আমি .Skip()আমার সংস্থার কোড বেসে অনেকগুলি পেয়েছি এবং তারা "অনুকূল" নাও থাকতে পারে তবে তারা ঠিক কাজ করে। ডিবি অপারেশনগুলির মতো জিনিসগুলি যাইহোক অনেক বেশি সময় নেয়। তবে আমি মনে করি যে .Skip()প্রতিটি উপাদানকে "স্পর্শ" করে এনথ-এলিমেন্টকে সরাসরি লাফিয়ে তোলার পরিবর্তে "ছোঁয়া" একটি গুরুত্বপূর্ণ বিষয় (যেমন আপনি আশা করতে পারেন)। যদি আপনার পুনরাবৃত্তকারীটির কোনও উপাদান স্পর্শ করা থেকে পার্শ্ব প্রতিক্রিয়া থাকে তবে খুঁজে পাওয়া .Skip()হার্ড-বাগের কারণ হতে পারে।
চক্রভা

11

সার্জ-টিএম সমাধানটি সূক্ষ্ম, এছাড়াও তালিকার জন্য এটি এক্সটেনশন পদ্ধতি হিসাবে জেনেরিক সংস্করণ (এটি একটি স্ট্যাটিক শ্রেণিতে রাখুন):

public static List<List<T>> Split<T>(this List<T> items, int sliceSize = 30)
{
    List<List<T>> list = new List<List<T>>();
    for (int i = 0; i < items.Count; i += sliceSize)
        list.Add(items.GetRange(i, Math.Min(sliceSize, items.Count - i)));
    return list;
} 

10

আমি গ্রহণযোগ্য উত্তর (সেরজ-টিএম) সর্বাধিক শক্তিশালী পেয়েছি তবে আমি একটি জেনেরিক সংস্করণ প্রস্তাব করতে চাই।

public static List<List<T>> splitList<T>(List<T> locations, int nSize = 30)
{
    var list = new List<List<T>>();

    for (int i = 0; i < locations.Count; i += nSize)
    {
        list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i)));
    }

    return list;
}

8

লাইব্রেরি মোড়লিংক পদ্ধতিতে ডাকা হয়েছে Batch

List<int> ids = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; // 10 elements
int counter = 1;
foreach(var batch in ids.Batch(2))
{
    foreach(var eachId in batch)
    {
        Console.WriteLine("Batch: {0}, Id: {1}", counter, eachId);
    }
    counter++;
}

ফলাফল হয়

Batch: 1, Id: 1
Batch: 1, Id: 2
Batch: 2, Id: 3
Batch: 2, Id: 4
Batch: 3, Id: 5
Batch: 3, Id: 6
Batch: 4, Id: 7
Batch: 4, Id: 8
Batch: 5, Id: 9
Batch: 5, Id: 0

ids 2 টি উপাদান দিয়ে 5 টি ভাগে বিভক্ত করা হয়।


এটির স্বীকৃত উত্তর হওয়া দরকার। অথবা এই পৃষ্ঠায় কমপক্ষে অনেক বেশি।
জার শারদান

7

আমার একটি জেনেরিক পদ্ধতি রয়েছে যা কোনও প্রকারের ফ্লোট অন্তর্ভুক্ত করবে এবং এটি ইউনিট-টেস্ট করা হয়েছে, আশা করি এটি সহায়তা করে:

    /// <summary>
    /// Breaks the list into groups with each group containing no more than the specified group size
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="values">The values.</param>
    /// <param name="groupSize">Size of the group.</param>
    /// <returns></returns>
    public static List<List<T>> SplitList<T>(IEnumerable<T> values, int groupSize, int? maxCount = null)
    {
        List<List<T>> result = new List<List<T>>();
        // Quick and special scenario
        if (values.Count() <= groupSize)
        {
            result.Add(values.ToList());
        }
        else
        {
            List<T> valueList = values.ToList();
            int startIndex = 0;
            int count = valueList.Count;
            int elementCount = 0;

            while (startIndex < count && (!maxCount.HasValue || (maxCount.HasValue && startIndex < maxCount)))
            {
                elementCount = (startIndex + groupSize > count) ? count - startIndex : groupSize;
                result.Add(valueList.GetRange(startIndex, elementCount));
                startIndex += elementCount;
            }
        }


        return result;
    }

ধন্যবাদ। যদি আপনি ম্যাক্সকাউন্টের প্যারামিটার সংজ্ঞা দিয়ে মন্তব্যগুলি আপডেট করতে পারেন তবে আশ্চর্য? একটি নিরাপত্তা জাল?
অ্যান্ড্রু জেনস

2
গণনার একাধিক গণনা সম্পর্কে সতর্কতা অবলম্বন করুন। values.Count()একটি সম্পূর্ণ গণনা এবং তারপরে values.ToList()অন্যটির কারণ ঘটবে । values = values.ToList()এটি করতে নিরাপদ এটি ইতিমধ্যে বাস্তবায়িত হয়েছে।
mhand

7

উপরের উত্তরগুলিতে প্রচুর পরিমাণে কাজ করা হলেও এগুলি সবই কখনও শেষ না হওয়া ক্রম (বা সত্যই দীর্ঘ ক্রম) এ ভয়াবহভাবে ব্যর্থ হয়। নিম্নলিখিতটি একটি সম্পূর্ণ অন-লাইনের বাস্তবায়ন যা সম্ভাব্য সেরা সময় এবং মেমরির জটিলতার গ্যারান্টি দেয়। আমরা উত্সটি ঠিক একবারে গণনার জন্য পুনরাবৃত্তি করি এবং অলস মূল্যায়নের জন্য ফলন ফেরত ব্যবহার করি। ভোক্তা প্রতিটি পুনরাবৃত্তির তালিকাকে মেমরির পদচিহ্নের তালিকা batchSizeও উপাদানগুলির সংখ্যার সমান করে ফেলে দিতে পারে ।

public static IEnumerable<List<T>> BatchBy<T>(this IEnumerable<T> enumerable, int batchSize)
{
    using (var enumerator = enumerable.GetEnumerator())
    {
        List<T> list = null;
        while (enumerator.MoveNext())
        {
            if (list == null)
            {
                list = new List<T> {enumerator.Current};
            }
            else if (list.Count < batchSize)
            {
                list.Add(enumerator.Current);
            }
            else
            {
                yield return list;
                list = new List<T> {enumerator.Current};
            }
        }

        if (list?.Count > 0)
        {
            yield return list;
        }
    }
}

সম্পাদনা: ঠিক এখন ওপিকে বুঝতে পেরে একটি List<T>ছোট ভাঙ্গার বিষয়ে জিজ্ঞাসা করেছে List<T>, সুতরাং অসীম গণনার বিষয়ে আমার মন্তব্যগুলি ওপি-র ক্ষেত্রে প্রযোজ্য নয়, তবে অন্যদের যারা এখানে এসেছেন তাদের সহায়তা করতে পারে। এই মন্তব্যগুলি অন্যান্য পোস্ট সমাধানগুলির প্রতিক্রিয়া IEnumerable<T>হিসাবেছিল যা তাদের ফাংশনটির ইনপুট হিসাবে ব্যবহার করে, তবুও উত্সকে একাধিকবার গণনা করতে পারে।


আমি মনে করি IEnumerable<IEnumerable<T>>সংস্করণটি আরও ভাল কারণ এটি এত বেশি Listনির্মাণের সাথে জড়িত নয় ।
নেটমেজ

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

আপনি ঠিক বলেছেন - আমার বাস্তবায়নটিতে একটি নতুন ধরণের গণক ব্যবহার করা হয় (পজিশন এনুমरेटर) যা আপনার বর্তমান অবস্থানকে একটি স্ট্যান্ডার্ড গণককে মোড়কে ট্র্যাক করে এবং আপনাকে নতুন অবস্থানে নিয়ে যেতে দেয়।
নেটমেজ

6

শেষে মোন্ড সম্পর্কে খুব দরকারী মন্তব্য পরে সংযোজন

আসল উত্তর

যদিও বেশিরভাগ সমাধানগুলি কার্যকর হতে পারে, আমি মনে করি সেগুলি খুব দক্ষতার সাথে নয়। মনে করুন আপনি যদি প্রথম কয়েকটি অংশের প্রথম কয়েকটি আইটেম চান তবে। তারপরে আপনি আপনার অনুক্রমের সমস্ত (জিলিয়ন) আইটেমগুলিতে পুনরাবৃত্তি করতে চান না।

নিম্নলিখিতগুলি সর্বদা দু'বার গণনা করা হবে: একবার নেওয়ার জন্য এবং একবার এড়িয়ে যান। এটি আপনার ব্যবহারের চেয়ে আরও বেশি উপাদানের উপরে গণনা করবে না:

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 () কল করা বুদ্ধিমান কিনা তা এটি আপনার সংগ্রহস্থলের উপর নির্ভর করে


এই প্রতি ব্যাচ দুইবার গণনা করা হবে না ? সুতরাং আমরা সত্যিই উত্স 2*chunkSizeবার গণনা করছি ? এটি গণনার উত্সের উপর নির্ভর করে মারাত্মক (সম্ভবত ডিবি ব্যাকড, বা অন্যান্য অ-স্মরণীয় উত্স)। ইনপুট হিসেবে এই গণনীয় কল্পনা Enumerable.Range(0, 10000).Select(i => DateTime.UtcNow)- আপনি বিভিন্ন সময় প্রত্যেক সময় আপনি গণনীয় যেহেতু এটি memoized না গনা পাবেন
mhand

বিবেচনা করুন: Enumerable.Range(0, 10).Select(i => DateTime.UtcNow)। অনুরোধ করে Anyআপনি প্রতিবারের সাথে পুনঃনির্মাণ করতে পারবেন। এর জন্য এতটা খারাপ নয় DateTime.UtcNow, তবে একটি ডাটাবেস সংযোগ / স্কোয়াএল কার্সার বা এর অনুরূপ দ্বারা গণ্য করা গণনা বিবেচনা করুন। আমি ক্ষেত্রে যেখানে ডিবি কল হাজার হাজার জারি হয়েছে কারণ ডেভেলপার 'একটি গণনীয় একাধিক enumerations' সম্ভাব্য প্রতিক্রিয়া বুঝতে পারে না দেখা করেছি - ReSharper এই জন্য একটি ইঙ্গিতটি পাশাপাশি প্রদান করে
mhand

4
public static IEnumerable<IEnumerable<T>> SplitIntoSets<T>
    (this IEnumerable<T> source, int itemsPerSet) 
{
    var sourceList = source as List<T> ?? source.ToList();
    for (var index = 0; index < sourceList.Count; index += itemsPerSet)
    {
        yield return sourceList.Skip(index).Take(itemsPerSet);
    }
}

3
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, int maxItems)
{
    return items.Select((item, index) => new { item, index })
                .GroupBy(x => x.index / maxItems)
                .Select(g => g.Select(x => x.item));
}

2

এটা কেমন? ধারণা ছিল কেবল একটি লুপ ব্যবহার করা। এবং কে জানে, সম্ভবত আপনি কেবলমাত্র আইলিস্ট প্রয়োগগুলি আপনার কোডটি পুরোপুরি ব্যবহার করছেন এবং আপনি তালিকায় কাস্ট করতে চান না।

private IEnumerable<IList<T>> SplitList<T>(IList<T> list, int totalChunks)
{
    IList<T> auxList = new List<T>();
    int totalItems = list.Count();

    if (totalChunks <= 0)
    {
        yield return auxList;
    }
    else 
    {
        for (int i = 0; i < totalItems; i++)
        {               
            auxList.Add(list[i]);           

            if ((i + 1) % totalChunks == 0)
            {
                yield return auxList;
                auxList = new List<T>();                
            }

            else if (i == totalItems - 1)
            {
                yield return auxList;
            }
        }
    }   
}

1

আরো একটা

public static IList<IList<T>> SplitList<T>(this IList<T> list, int chunkSize)
{
    var chunks = new List<IList<T>>();
    List<T> chunk = null;
    for (var i = 0; i < list.Count; i++)
    {
        if (i % chunkSize == 0)
        {
            chunk = new List<T>(chunkSize);
            chunks.Add(chunk);
        }
        chunk.Add(list[i]);
    }
    return chunks;
}

1
public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize)
    {           
        var result = new List<List<T>>();
        for (int i = 0; i < source.Count; i += chunkSize)
        {
            var rows = new List<T>();
            for (int j = i; j < i + chunkSize; j++)
            {
                if (j >= source.Count) break;
                rows.Add(source[j]);
            }
            result.Add(rows);
        }
        return result;
    }

0
List<int> list =new List<int>(){1,2,3,4,5,6,7,8,9,10,12};
Dictionary<int,List<int>> dic = new Dictionary <int,List<int>> ();
int batchcount = list.Count/2; //To List into two 2 parts if you want three give three
List<int> lst = new List<int>();
for (int i=0;i<list.Count; i++)
{
lstdocs.Add(list[i]);
if (i % batchCount == 0 && i!=0)
{
Dic.Add(threadId, lstdocs);
lst = new List<int>();**strong text**
threadId++;
}
}
Dic.Add(threadId, lstdocs);

2
কেবলমাত্র একটি কোড স্নিপেট সরবরাহ করার চেয়ে আপনার উত্তরটি ব্যাখ্যা করা ভাল
কেভিন

0

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

        var categories = Properties.Settings.Default.MovementStatsCategories;
        var items = summariesWithinYear
            .Select(s =>  s.sku).Distinct().ToList();

        //need to run by chunks of 10,000
        var count = items.Count;
        var counter = 0;
        var numToTake = 10000;

        while (count > 0)
        {
            var itemsChunk = items.Skip(numToTake * counter).Take(numToTake).ToList();
            counter += 1;

            MovementHistoryUtilities.RecordMovementHistoryStatsBulk(itemsChunk, categories, nLogger);

            count -= numToTake;
        }

0

উপর ভিত্তি করে Dimitry পাভলভ answere আমি মুছে ফেলা হবে .ToList()। এবং বেনামে ক্লাস এড়ানো। পরিবর্তে আমি এমন কাঠামো ব্যবহার করতে চাই যার জন্য হিপ মেমরির বরাদ্দ প্রয়োজন হয় না। ( ValueTupleএও চাকরি করবে))

public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>(this IEnumerable<TSource> source, int chunkSize)
{
    if (source is null)
    {
        throw new ArgumentNullException(nameof(source));
    }
    if (chunkSize <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(chunkSize), chunkSize, "The argument must be greater than zero.");
    }

    return source
        .Select((x, i) => new ChunkedValue<TSource>(x, i / chunkSize))
        .GroupBy(cv => cv.ChunkIndex)
        .Select(g => g.Select(cv => cv.Value));
} 

[StructLayout(LayoutKind.Auto)]
[DebuggerDisplay("{" + nameof(ChunkedValue<T>.ChunkIndex) + "}: {" + nameof(ChunkedValue<T>.Value) + "}")]
private struct ChunkedValue<T>
{
    public ChunkedValue(T value, int chunkIndex)
    {
        this.ChunkIndex = chunkIndex;
        this.Value = value;
    }

    public int ChunkIndex { get; }

    public T Value { get; }
}

এটি নিম্নলিখিতগুলির মতো ব্যবহার করা যেতে পারে যা কেবল একবার সংগ্রহের উপরে পুনরাবৃত্তি করে এবং কোনও উল্লেখযোগ্য মেমরি বরাদ্দ করে না।

int chunkSize = 30;
foreach (var chunk in collection.ChunkBy(chunkSize))
{
    foreach (var item in chunk)
    {
        // your code for item here.
    }
}

যদি কংক্রিটের তালিকার প্রয়োজন হয় তবে আমি এটি এইভাবে করব:

int chunkSize = 30;
var chunkList = new List<List<T>>();
foreach (var chunk in collection.ChunkBy(chunkSize))
{
    // create a list with the correct capacity to be able to contain one chunk
    // to avoid the resizing (additional memory allocation and memory copy) within the List<T>.
    var list = new List<T>(chunkSize);
    list.AddRange(chunk);
    chunkList.Add(list);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.