आप सकता है प्रश्नों का उपयोग करने वाले के एक नंबर का उपयोग 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
:
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>
प्रत्येक आइटम के माध्यम से मैन्युअल रूप से प्रसारित हो जाता है । यह देखने के लिए जांचता है कि क्या वर्तमान में कोई आइटम एनुमरेटेड है। प्रत्येक चंक के माध्यम से एनुमरेट किया जाता है, अगर कोई आइटम नहीं बचा है, तो यह टूट जाता है।
एक बार जब यह पता चलता है कि अनुक्रम में आइटम हैं, तो यह आंतरिक IEnumerable<T>
कार्यान्वयन के लिए जिम्मेदारी को दर्शाता है 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
पहले से ही इसे IEnumerator<T>
पास करने के लिए बुलाया गया था ChunkSequence
, इसलिए यह आइटम द्वारा लौटाए गए पैदावार को Current
बढ़ाता है और फिर गणना में वृद्धि करता है, जिससे यह सुनिश्चित होता है कि chunkSize
आइटम से अधिक कभी नहीं लौटाएं और प्रत्येक पुनरावृत्ति के बाद अनुक्रम में अगले आइटम पर जा रहे हैं (लेकिन शॉर्ट-सर्कुलेट किया गया है यदि संख्या प्राप्त उपज चंक आकार से अधिक है)।
यदि कोई आइटम नहीं बचा है, तो InternalChunk
विधि बाहरी लूप में एक और पास करेगी, लेकिन जब MoveNext
दूसरी बार कहा जाता है, तो यह अभी भी दस्तावेज़ (जोर मेरा) के अनुसार , झूठी वापस आ जाएगी :
यदि MoveNext संग्रह के अंत से गुजरता है, तो संग्रह में अंतिम तत्व के बाद Enumerator तैनात किया जाता है और 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,
एक महत्वपूर्ण नोट, यह काम नहीं करेगा यदि आप पूरे बच्चे के अनुक्रम को सूखा नहीं देते हैं या माता-पिता के अनुक्रम में किसी भी बिंदु पर टूट जाते हैं। यह एक महत्वपूर्ण चेतावनी है, लेकिन यदि आपका उपयोग मामला यह है कि आप अनुक्रम के प्रत्येक तत्व का उपभोग करेंगे , तो यह आपके लिए काम करेगा।
इसके अतिरिक्त, यह अजीब चीजें करेगा यदि आप आदेश के साथ खेलते हैं, जैसे कि सैम ने एक बिंदु पर किया था ।