दिलचस्प पोस्ट
सरणी से सबसे निकटतम संख्या प्राप्त करें हैशडोड () कैसे सुनिश्चित करने के लिए बराबर () के अनुरूप है? यह निर्धारित कैसे करें कि नेटवर्क प्रकार 2 जी, 3 जी या 4 जी है एंड्रॉइड मैप एक्टिविटी: कनेक्शन फ़ैक्टरी क्लाइंट नहीं मिल सका रेगएक्स: उद्धरण चिह्नों के बीच मूल्यों को हथियाने विंडोस्टेट को न्यूनतम से पुनर्स्थापित करें चेहरालेट (जेएसएफ) और एक्सएचटीएमएल के साथ ग्रहण स्वत: पूर्ण (सामग्री सहायता) ओएस एक्स पर सी ++ लाइब्रेरी स्थापित करना .NET: क्या एचटीटीपीएबआरएइवेईस्ट को जीज़िप प्रतिक्रियाओं को स्वतः डीकंप्रेस करना संभव है? pysqlite: स्तंभ या मेज के नाम के लिए प्लेसहोल्डर प्रतिस्थापन? JQuery.ajax के साथ मल्टीपार्ट / फॉर्मडाटा भेजा जा रहा है फ़ंक्शन के पास जाने वाले वेरिएबल के मूल वैरिएबल नाम कैसे प्राप्त करें क्या मुझे SQL सर्वर में थोड़ी फ़ील्ड को अनुक्रमणिका चाहिए? (अंतरण) के बीच अंतर क्या है। टूलीस्ट (),। अतुलनीय (), एन्कॉटेबल ()? LoadFile और लोड के बीच अंतर। नेट विधानसभाओं के साथ?

LINQ के साथ Sublists में विभाजित सूची

क्या कोई तरीका है कि मैं कुछ List<SomeObject> कई अलग सूची में एक List<SomeObject> अलग कर सकता SomeObject , आइटम सूचकांक को प्रत्येक विभाजन के सीमांकक के रूप में प्रयोग कर रहा SomeObject ?

मुझे उदाहरण देते हैं:

मेरे पास एक List<SomeObject> और मुझे एक List<List<SomeObject>> या List<SomeObject>[] , ताकि इनकी प्रत्येक सूची में मूल सूची (क्रमिक रूप से) के 3 आइटम के समूह होंगे।

उदा .:

  • मूल सूची: [a, g, e, w, p, s, q, f, x, y, i, m, c]

  • परिणामस्वरूप सूचियां: [a, g, e], [w, p, s], [q, f, x], [y, i, m], [c]

इस फ़ंक्शन के पैरामीटर होने के लिए मुझे इसके परिणामस्वरूप सूचियों के आकार की भी आवश्यकता होगी

वेब के समाधान से एकत्रित समाधान "LINQ के साथ Sublists में विभाजित सूची"

निम्न कोड को आज़माएं

 public static IList<IList<T>> Split<T>(IList<T> source) { return source .Select((x, i) => new { Index = i, Value = x }) .GroupBy(x => x.Index / 3) .Select(x => x.Select(v => v.Value).ToList()) .ToList(); } 

यह विचार पहले समूह को अनुक्रमित द्वारा तत्वों के लिए है। तीनों को विभाजित करने से उन्हें 3 समूहों के समूह में बांटने का असर होता है। फिर प्रत्येक समूह को एक सूची में परिवर्तित करें और List की एक List में List के IEnumerable परिवर्तित करें

यह सवाल थोड़ा पुराना है, लेकिन मैंने इसे लिखा है, और मुझे लगता है कि यह अन्य प्रस्तावित समाधानों की तुलना में थोड़ा अधिक सुरुचिपूर्ण है:

 /// <summary> /// Break a list of items into chunks of a specific size /// </summary> public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize) { while (source.Any()) { yield return source.Take(chunksize); source = source.Skip(chunksize); } } 

सामान्य तौर पर केसीबी द्वारा सुझाव दिया गया दृष्टिकोण ठीक काम करता है, वास्तव में यदि आप एक List<T> में गुजर रहे हैं तो यह गलती मुश्किल है, शायद मैं इसे बदलूंगा :

 public static IEnumerable<IEnumerable<T>> ChunkTrivialBetter<T>(this IEnumerable<T> source, int chunksize) { var pos = 0; while (source.Skip(pos).Any()) { yield return source.Skip(pos).Take(chunksize); pos += chunksize; } } 

जो बड़े पैमाने पर कॉल चेन से बचना होगा। बहरहाल, इस दृष्टिकोण का एक सामान्य दोष है इस मुद्दे को उजागर करने के लिए प्रत्येक चोका दो एन्यूमरेशन का आशय बढ़ाया जा रहा है:

 foreach (var item in Enumerable.Range(1, int.MaxValue).Chunk(8).Skip(100000).First()) { Console.WriteLine(item); } // wait forever 

इस पर काबू पाने के लिए हम कैमरन के दृष्टिकोण की कोशिश कर सकते हैं, जो उपरोक्त परीक्षण को उड़ने वाले रंगों में गुजरता है क्योंकि यह केवल एक बार गणना को चलता है।

मुसीबत यह है कि इसकी एक अलग खामी है, यह हर चीज में प्रत्येक वस्तु को माहिर करता है, इस दृष्टिकोण के साथ परेशानी यह है कि आप स्मृति पर उच्च चलाते हैं

उदाहरण के लिए कि चलने का प्रयास करें:

 foreach (var item in Enumerable.Range(1, int.MaxValue) .Select(x => x + new string('x', 100000)) .Clump(10000).Skip(100).First()) { Console.Write('.'); } // OutOfMemoryException 

अंत में, किसी भी कार्यान्वयन को विखंडों के आदेश पुनरावृत्ति से निपटने में सक्षम होना चाहिए, उदाहरण के लिए:

 Enumerable.Range(1,3).Chunk(2).Reverse.ToArray() // should return [3],[1,2] 

इस उत्तर की मेरी पहली संशोधन की तरह कई बेहद अनुकूल समाधान विफल रहे। कैस्परऑन के अनुकूलित उत्तर में एक ही समस्या देखी जा सकती है।

इन सभी समस्याओं का समाधान करने के लिए आप निम्न का उपयोग कर सकते हैं:

 namespace ChunkedEnumerator { public static class Extensions { class ChunkedEnumerable<T> : IEnumerable<T> { class ChildEnumerator : IEnumerator<T> { ChunkedEnumerable<T> parent; int position; bool done = false; T current; public ChildEnumerator(ChunkedEnumerable<T> parent) { this.parent = parent; position = -1; parent.wrapper.AddRef(); } public T Current { get { if (position == -1 || done) { throw new InvalidOperationException(); } return current; } } public void Dispose() { if (!done) { done = true; parent.wrapper.RemoveRef(); } } object System.Collections.IEnumerator.Current { get { return Current; } } public bool MoveNext() { position++; if (position + 1 > parent.chunkSize) { done = true; } if (!done) { done = !parent.wrapper.Get(position + parent.start, out current); } return !done; } public void Reset() { // per http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx throw new NotSupportedException(); } } EnumeratorWrapper<T> wrapper; int chunkSize; int start; public ChunkedEnumerable(EnumeratorWrapper<T> wrapper, int chunkSize, int start) { this.wrapper = wrapper; this.chunkSize = chunkSize; this.start = start; } public IEnumerator<T> GetEnumerator() { return new ChildEnumerator(this); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } class EnumeratorWrapper<T> { public EnumeratorWrapper (IEnumerable<T> source) { SourceEumerable = source; } IEnumerable<T> SourceEumerable {get; set;} Enumeration currentEnumeration; class Enumeration { public IEnumerator<T> Source { get; set; } public int Position { get; set; } public bool AtEnd { get; set; } } public bool Get(int pos, out T item) { if (currentEnumeration != null && currentEnumeration.Position > pos) { currentEnumeration.Source.Dispose(); currentEnumeration = null; } if (currentEnumeration == null) { currentEnumeration = new Enumeration { Position = -1, Source = SourceEumerable.GetEnumerator(), AtEnd = false }; } item = default(T); if (currentEnumeration.AtEnd) { return false; } while(currentEnumeration.Position < pos) { currentEnumeration.AtEnd = !currentEnumeration.Source.MoveNext(); currentEnumeration.Position++; if (currentEnumeration.AtEnd) { return false; } } item = currentEnumeration.Source.Current; return true; } int refs = 0; // needed for dispose semantics public void AddRef() { refs++; } public void RemoveRef() { refs--; if (refs == 0 && currentEnumeration != null) { var copy = currentEnumeration; currentEnumeration = null; copy.Source.Dispose(); } } } public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize) { if (chunksize < 1) throw new InvalidOperationException(); var wrapper = new EnumeratorWrapper<T>(source); int currentPos = 0; T ignore; try { wrapper.AddRef(); while (wrapper.Get(currentPos, out ignore)) { yield return new ChunkedEnumerable<T>(wrapper, chunksize, currentPos); currentPos += chunksize; } } finally { wrapper.RemoveRef(); } } } class Program { static void Main(string[] args) { int i = 10; foreach (var group in Enumerable.Range(1, int.MaxValue).Skip(10000000).Chunk(3)) { foreach (var n in group) { Console.Write(n); Console.Write(" "); } Console.WriteLine(); if (i-- == 0) break; } var stuffs = Enumerable.Range(1, 10).Chunk(2).ToArray(); foreach (var idx in new [] {3,2,1}) { Console.Write("idx " + idx + " "); foreach (var n in stuffs[idx]) { Console.Write(n); Console.Write(" "); } Console.WriteLine(); } /* 10000001 10000002 10000003 10000004 10000005 10000006 10000007 10000008 10000009 10000010 10000011 10000012 10000013 10000014 10000015 10000016 10000017 10000018 10000019 10000020 10000021 10000022 10000023 10000024 10000025 10000026 10000027 10000028 10000029 10000030 10000031 10000032 10000033 idx 3 7 8 idx 2 5 6 idx 1 3 4 */ Console.ReadKey(); } } } 

वहाँ भी एक दौर का अनुकूलन है जिसे आप विखंडों के आउट-ऑफ-ऑर्डरेशन के लिए पेश कर सकते हैं, जो कि यहां से बाहर नहीं है

किस विधि के लिए आपको चुनना चाहिए? यह पूरी तरह से उस समस्या पर निर्भर करता है जिसे आप हल करने की कोशिश कर रहे हैं। यदि आप पहले दोष से संबंधित नहीं हैं तो साधारण उत्तर अविश्वसनीय रूप से अपील कर रहा है।

अधिकांश तरीकों के साथ ध्यान रखें , यह बहु थ्रेडिंग के लिए सुरक्षित नहीं है, सामान अजीब हो सकता है यदि आप इसे थ्रेड सुरक्षित बनाना चाहते हैं तो आपको EnumeratorWrapper को संशोधित करने की आवश्यकता होगी।

आप कई सारे प्रश्नों का उपयोग कर सकते हैं जो Take और Skip उपयोग करते हैं, लेकिन यह मूल सूची पर बहुत अधिक पुनरावृत्तियों को जोड़ देगा, मुझे विश्वास है।

बल्कि, मुझे लगता है कि आपको अपनी तरह से एक इटरेटर बनाने चाहिए, जैसे:

 public static IEnumerable<IEnumerable<T>> GetEnumerableOfEnumerables<T>( IEnumerable<T> enumerable, int groupSize) { // The list to return. List<T> list = new List<T>(groupSize); // Cycle through all of the items. foreach (T item in enumerable) { // Add the item. list.Add(item); // If the list has the number of elements, return that. if (list.Count == groupSize) { // Return the list. yield return list; // Set the list to a new list. list = new List<T>(groupSize); } } // Return the remainder if there is any, if (list.Count != 0) { // Return the list. yield return list; } } 

आप इसे कॉल कर सकते हैं और यह LINQ सक्षम है ताकि आप परिणामी अनुक्रमों पर अन्य ऑपरेशन कर सकें।


सैम के उत्तर के प्रकाश में, मुझे लगा कि बिना यह करने का एक आसान तरीका था:

  • सूची के माध्यम से फिर से फेरबदल (जो मैंने मूल रूप से नहीं किया था)
  • खंड को जारी करने से पहले समूह में आइटमों को सामंजस्य बनाना (वस्तुओं के बड़े हिस्से के लिए, स्मृति समस्याएं होंगी)
  • सभी कोड जो सैम ने पोस्ट किया

उस ने कहा, यहाँ एक और पास है, जिसने मैंने विस्तारित विधि के लिए IEnumerable<T> बुलाया Chunk :

 public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize) { // Validate parameters. if (source == null) throw new ArgumentNullException("source"); if (chunkSize <= 0) throw new ArgumentOutOfRangeException("chunkSize", "The chunkSize parameter must be a positive value."); // Call the internal implementation. return source.ChunkInternal(chunkSize); } 

वहाँ कोई आश्चर्य की बात नहीं है, सिर्फ बुनियादी त्रुटि की जांच

ChunkInternal पर ChunkInternal :

 private static IEnumerable<IEnumerable<T>> ChunkInternal<T>( this IEnumerable<T> source, int chunkSize) { // Validate parameters. Debug.Assert(source != null); Debug.Assert(chunkSize > 0); // Get the enumerator. Dispose of when done. using (IEnumerator<T> enumerator = source.GetEnumerator()) do { // Move to the next element. If there's nothing left // then get out. if (!enumerator.MoveNext()) yield break; // Return the chunked sequence. yield return ChunkSequence(enumerator, chunkSize); } while (true); } 

असल में, यह IEnumerator<T> हो जाता है और मैन्युअल रूप से प्रत्येक आइटम के माध्यम से पुनरावृत्त करता है यह देखने के लिए जांचता है कि क्या वर्तमान में इनकी गणना के लिए कोई आइटम हैं। प्रत्येक खंड के माध्यम से गणना की जाती है, अगर कोई आइटम नहीं छोड़ेगा, तो यह टूट जाएगा।

एक बार जब यह पता चलता है कि अनुक्रम में आइटम हैं, तो वह आंतरिक ChunkSequence IEnumerable<T> कार्यान्वयन से ChunkSequence लिए ChunkSequence :

 private static IEnumerable<T> ChunkSequence<T>(IEnumerator<T> enumerator, int chunkSize) { // Validate parameters. Debug.Assert(enumerator != null); Debug.Assert(chunkSize > 0); // The count. int count = 0; // There is at least one item. Yield and then continue. do { // Yield the item. yield return enumerator.Current; } while (++count < chunkSize && enumerator.MoveNext()); } 

चूंकि MoveNext को पहले से ही ChunkSequence IEnumerator<T> ChunkSequence पास भेजा गया ChunkSequence , यह Current लौटाए गए आइटम को पैदा करता है और उसके बाद गिनती में वृद्धि करता है, यह सुनिश्चित करता है कि chunkSize से अधिक कभी भी वापस न chunkSize और हर वस्तु के बाद अनुक्रम में अगले आइटम पर chunkSize ( लेकिन कम-सर्किट यदि मदों की संख्या अधिक होती है तो चक आकार से अधिक होता है)।

अगर कोई आइटम नहीं छोड़ेगा, तो InternalChunk विधि बाहरी लूप में एक और MoveNext करेगी, लेकिन जब MoveNext को दूसरी बार कहा जाता है, तो यह अभी भी गलत होगा, प्रलेखन (जोर खान) के अनुसार:

यदि हांगएक्स्ट संग्रह के अंत में गुजरता है, तो गणनाकर्ता संग्रह में अंतिम तत्व के बाद स्थानांतरित होता है और हां, आगे, झूठी वापसी करता है। जब गणक इस स्थिति में होता है, तो अगली कॉल की ओर जाने के लिए जब भी रीसेट को कहा जाता है, तो आगे की कॉल भी गलत लौटाते हैं।

इस बिंदु पर, लूप टूट जाएगा, और दृश्यों का क्रम समाप्त होगा।

यह एक साधारण परीक्षण है:

 static void Main() { string s = "agewpsqfxyimc"; int count = 0; // Group by three. foreach (IEnumerable<char> g in s.Chunk(3)) { // Print out the group. Console.Write("Group: {0} - ", ++count); // Print the items. foreach (char c in g) { // Print the item. Console.Write(c + ", "); } // Finish the line. Console.WriteLine(); } } 

आउटपुट:

 Group: 1 - a, g, e, Group: 2 - w, p, s, Group: 3 - q, f, x, Group: 4 - y, i, m, Group: 5 - c, 

एक महत्वपूर्ण नोट, यह काम नहीं करेगा यदि आप पूरे बच्चे के अनुक्रम को न निकालें या माता-पिता अनुक्रम में किसी भी बिंदु पर तोड़ दें। यह एक महत्वपूर्ण चेतावनी है, लेकिन यदि आपके उपयोग का मामला यह है कि आप अनुक्रमों के अनुक्रम के प्रत्येक तत्व का प्रयोग करेंगे, तो यह आपके लिए काम करेगा।

इसके अतिरिक्त, यदि आप ऑर्डर से खेलते हैं, तो जैसे ही सैम एक ही समय में यह अजीब काम करता है।

ठीक है, यहां पर ये मेरा लेना है:

  • पूरी तरह आलसी: अनन्त गणक पर काम करता है
  • कोई मध्यवर्ती नकल / बफरिंग नहीं
  • ओ (एन) निष्पादन समय
  • तब भी काम करता है जब आंतरिक अनुक्रम केवल आंशिक रूप से खपत होते हैं

 public static IEnumerable<IEnumerable<T>> Chunks<T>(this IEnumerable<T> enumerable, int chunkSize) { if (chunkSize < 1) throw new ArgumentException("chunkSize must be positive"); using (var e = enumerable.GetEnumerator()) while (e.MoveNext()) { var remaining = chunkSize; // elements remaining in the current chunk var innerMoveNext = new Func<bool>(() => --remaining > 0 && e.MoveNext()); yield return e.GetChunk(innerMoveNext); while (innerMoveNext()) {/* discard elements skipped by inner iterator */} } } private static IEnumerable<T> GetChunk<T>(this IEnumerator<T> e, Func<bool> innerMoveNext) { do yield return e.Current; while (innerMoveNext()); } 

उदाहरण उपयोग

 var src = new [] {1, 2, 3, 4, 5, 6}; var c3 = src.Chunks(3); // {{1, 2, 3}, {4, 5, 6}}; var c4 = src.Chunks(4); // {{1, 2, 3, 4}, {5, 6}}; var sum = c3.Select(c => c.Sum()); // {6, 15} var count = c3.Count(); // 2 var take2 = c3.Select(c => c.Take(2)); // {{1, 2}, {4, 5}} 

स्पष्टीकरण

यह कोड दो yield आधारित पुनरावृत्तियों के घोंसले के शिकार द्वारा काम करता है।

बाहरी इटरेटर को ध्यान रखना चाहिए कि आंतरिक (चक्का) इटरेटर द्वारा कितने तत्वों का प्रभावी ढंग से उपयोग किया गया है। इसे innerMoveNext() साथ remaining पर बंद करके किया जाता है। अगले चक्र से बाहर निकलने के पहले एक खंड के अव्यवस्थित तत्व को त्याग दिया जाता है। यह जरूरी है क्योंकि अन्यथा आपको असंगत परिणाम मिलते हैं, जब भीतर की संख्या (पूरी तरह से) भस्म नहीं होती है (उदाहरण के लिए c3.Count() वापस आ जाएगी 6)।

नोट: उत्तर को @ओलसवॉका द्वारा उठाए गए कमियों को पूरा करने के लिए अद्यतन किया गया है

पूरी तरह आलसी, कोई गिनती या नकल नहीं:

 public static class EnumerableExtensions { public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int len) { if (len == 0) throw new ArgumentNullException(); var enumer = source.GetEnumerator(); while (enumer.MoveNext()) { yield return Take(enumer.Current, enumer, len); } } private static IEnumerable<T> Take<T>(T head, IEnumerator<T> tail, int len) { while (true) { yield return head; if (--len == 0) break; if (tail.MoveNext()) head = tail.Current; else break; } } } 

मुझे लगता है कि निम्न सुझाव सबसे तेज़ होगा मैं ऐरे का उपयोग करने की क्षमता के लिए स्रोत के आलस्य का त्याग कर रहा हूं। कॉपी और मेरे प्रत्येक सुब्बिलिस्ट की लंबाई के बारे में जानने से पहले

 public static IEnumerable<T[]> Chunk<T>(this IEnumerable<T> items, int size) { T[] array = items as T[] ?? items.ToArray(); for (int i = 0; i < array.Length; i+=size) { T[] chunk = new T[Math.Min(size, array.Length - i)]; Array.Copy(array, i, chunk, 0, chunk.Length); yield return chunk; } } 

हम सच आलसी मूल्यांकन करने के लिए @ जेरेडपर्स के समाधान में सुधार कर सकते हैं। हम एक GroupAdjacentBy पद्धति का उपयोग करते हैं जो एक ही कुंजी के साथ लगातार तत्वों के समूह उत्पन्न करती हैं:

 sequence .Select((x, i) => new { Value = x, Index = i }) .GroupAdjacentBy(x=>x.Index/3) .Select(g=>g.Select(x=>x.Value)) 

चूंकि समूहों को एक-एक-एक करके मिलाया जाता है, इसलिए यह समाधान लंबे या अनंत अनुक्रमों के साथ कुशलता से काम करता है।

System.Interactive इस उद्देश्य के लिए Buffer() प्रदान करता है कुछ त्वरित परीक्षण से पता चलता है प्रदर्शन सैम के समाधान के समान है।

यहां कुछ महीने पहले मैंने एक लिस्ट स्प्लिटिंग रूटीन लिखा था:

 public static List<List<T>> Chunk<T>( List<T> theList, int chunkSize ) { List<List<T>> result = theList .Select((x, i) => new { data = x, indexgroup = i / chunkSize }) .GroupBy(x => x.indexgroup, x => x.data) .Select(g => new List<T>(g)) .ToList(); return result; } 

मैंने कई साल पहले क्लम्प विस्तार विधि लिखी थी। महान काम करता है, और सबसे तेजी से कार्यान्वयन यहाँ है : पी

 /// <summary> /// Clumps items into same size lots. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">The source list of items.</param> /// <param name="size">The maximum size of the clumps to make.</param> /// <returns>A list of list of items, where each list of items is no bigger than the size given.</returns> public static IEnumerable<IEnumerable<T>> Clump<T>(this IEnumerable<T> source, int size) { if (source == null) throw new ArgumentNullException("source"); if (size < 1) throw new ArgumentOutOfRangeException("size", "size must be greater than 0"); return ClumpIterator<T>(source, size); } private static IEnumerable<IEnumerable<T>> ClumpIterator<T>(IEnumerable<T> source, int size) { Debug.Assert(source != null, "source is null."); T[] items = new T[size]; int count = 0; foreach (var item in source) { items[count] = item; count++; if (count == size) { yield return items; items = new T[size]; count = 0; } } if (count > 0) { if (count == size) yield return items; else { T[] tempItems = new T[count]; Array.Copy(items, tempItems, count); yield return tempItems; } } } 

यह एक पुराना सवाल है, लेकिन यह मेरे साथ समाप्त हुआ है; यह केवल एक बार गणना करता है, लेकिन प्रत्येक विभाजन के लिए सूचियां बनायीं। यह अनपेक्षित व्यवहार से ग्रस्त नहीं होता जब ToArray() को कुछ कार्यान्वयन कहा जाता है:

  public static IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int chunkSize) { if (source == null) { throw new ArgumentNullException("source"); } if (chunkSize < 1) { throw new ArgumentException("Invalid chunkSize: " + chunkSize); } using (IEnumerator<T> sourceEnumerator = source.GetEnumerator()) { IList<T> currentChunk = new List<T>(); while (sourceEnumerator.MoveNext()) { currentChunk.Add(sourceEnumerator.Current); if (currentChunk.Count == chunkSize) { yield return currentChunk; currentChunk = new List<T>(); } } if (currentChunk.Any()) { yield return currentChunk; } } } 

मुझे यह छोटा स्निपेट लगता है काम काफी अच्छा है

 public static IEnumerable<List<T>> Chunked<T>(this List<T> source, int chunkSize) { var offset = 0; while (offset < source.Count) { yield return source.GetRange(offset, Math.Min(source.Count - offset, chunkSize)); offset += chunkSize; } } 

यह निम्नलिखित समाधान सबसे कॉम्पैक्ट है जिसके साथ मैं आ सकता हूं ओ (एन)।

 public static IEnumerable<T[]> Chunk<T>(IEnumerable<T> source, int chunksize) { var list = source as IList<T> ?? source.ToList(); for (int start = 0; start < list.Count; start += chunksize) { T[] chunk = new T[Math.Min(chunksize, list.Count - start)]; for (int i = 0; i < chunk.Length; i++) chunk[i] = list[start + i]; yield return chunk; } } 

पुराने कोड, लेकिन मैं यही प्रयोग कर रहा हूं:

  public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max) { var toReturn = new List<T>(max); foreach (var item in source) { toReturn.Add(item); if (toReturn.Count == max) { yield return toReturn; toReturn = new List<T>(max); } } if (toReturn.Any()) { yield return toReturn; } } 

यदि सूची type.collections.generic प्रकार की है तो आप अन्य उप एरे के लिए अपने सरणी के तत्वों की प्रतिलिपि बनाने के लिए "CopyTo" विधि का उपयोग कर सकते हैं। आप प्रतिलिपि बनाने के लिए प्रारंभ तत्व और तत्वों की संख्या निर्दिष्ट करते हैं।

आप अपनी मूल सूची के 3 क्लोन भी बना सकते हैं और प्रत्येक सूची पर "निकालेंरेन्ज" का उपयोग करके उस सूची को इच्छित आकार में सिकुड़ कर सकते हैं।

या बस आपके लिए यह करने के लिए एक सहायक विधि बनाएं।

हमने पाया कि डेविड बी के समाधान ने सबसे अच्छा काम किया लेकिन हमने इसे और अधिक सामान्य समाधान के रूप में रूपांतरित किया:

 list.GroupBy(item => item.SomeProperty) .Select(group => new List<T>(group)) .ToArray(); 

और इसका क्या?

 var input = new List<string> { "a", "g", "e", "w", "p", "s", "q", "f", "x", "y", "i", "m", "c" }; var k = 3 var res = Enumerable.Range(0, (input.Count - 1) / k + 1) .Select(i => input.GetRange(i * k, Math.Min(k, input.Count - i * k))) .ToList(); 

जहाँ तक मुझे पता है, GetRange () ली गई मदों की संख्या के अनुसार रैखिक है तो यह अच्छी तरह से प्रदर्शन करना चाहिए

मॉड्यूलर विभाजन का उपयोग करना:

 public IEnumerable<IEnumerable<string>> Split(IEnumerable<string> input, int chunkSize) { var chunks = (int)Math.Ceiling((double)input.Count() / (double)chunkSize); return Enumerable.Range(0, chunks).Select(id => input.Where(s => s.GetHashCode() % chunks == id)); } 

बस मेरे दो सेंट में डाल दिया यदि आप सूची में "बाल्टी" चाहते थे (बाएं से दाएं कल्पना), तो आप निम्न कर सकते हैं:

  public static List<List<T>> Buckets<T>(this List<T> source, int numberOfBuckets) { List<List<T>> result = new List<List<T>>(); for (int i = 0; i < numberOfBuckets; i++) { result.Add(new List<T>()); } int count = 0; while (count < source.Count()) { var mod = count % numberOfBuckets; result[mod].Add(source[count]); count++; } return result; } 

यह एक पुराना समाधान है लेकिन मेरे पास एक अलग दृष्टिकोण था। मैं ऑफसेट वांछित करने के लिए ले जाने के लिए Skip हूं और इच्छित तत्वों की संख्या निकालने के लिए ले जाता हूं:

 public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize) { if (chunkSize <= 0) throw new ArgumentOutOfRangeException($"{nameof(chunkSize)} should be > 0"); var nbChunks = (int)Math.Ceiling((double)source.Count()/chunkSize); return Enumerable.Range(0, nbChunks) .Select(chunkNb => source.Skip(chunkNb*chunkSize) .Take(chunkSize)); } 

मैंने प्राथमिक जवाब लिया और यह निर्धारित करने के लिए कि I ( जो वास्तव में केवल 3 आइटम पर विभाजित है, इस पद को पढ़ने के दौरान एक जवाब की तलाश करते हुए कौन? )

This method allows one to split on any type of item as needed.

 public static List<List<T>> SplitOn<T>(List<T> main, Func<T, bool> splitOn) { int groupIndex = 0; return main.Select( item => new { Group = (splitOn.Invoke(item) ? ++groupIndex : groupIndex), Value = item }) .GroupBy( it2 => it2.Group) .Select(x => x.Select(v => v.Value).ToList()) .ToList(); } 

So for the OP the code would be

 var it = new List<string>() { "a", "g", "e", "w", "p", "s", "q", "f", "x", "y", "i", "m", "c" }; int index = 0; var result = SplitOn(it, (itm) => (index++ % 3) == 0 ); 

To insert my two cents…

By using the list type for the source to be chunked, I found another very compact solution:

 public static IEnumerable<IEnumerable<TSource>> Chunk<TSource>(this IEnumerable<TSource> source, int chunkSize) { // copy the source into a list var chunkList = source.ToList(); // return chunks of 'chunkSize' items while (chunkList.Count > chunkSize) { yield return chunkList.GetRange(0, chunkSize); chunkList.RemoveRange(0, chunkSize); } // return the rest yield return chunkList; }