Sen olabilir kullanmak sorgu numarasını kullanmak Take
veSkip
, ama bu orijinal listedeki çok fazla tekrarlamalar eklersiniz, inanıyorum.
Bunun yerine, kendi yinelemenizi oluşturmanız gerektiğini düşünüyorum:
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;
}
}
Daha sonra bunu çağırabilirsiniz ve LINQ etkinleştirilir, böylece sonuçlanan diziler üzerinde diğer işlemleri gerçekleştirebilirsiniz.
Sam'in cevabının ışığında, bunu yapmadan daha kolay bir yol olduğunu hissettim:
- Listeyi tekrar tekrar (ilk başta yapmadığım)
- Yığını serbest bırakmadan önce öğeleri gruplar halinde gerçekleştirme (öğelerin büyük parçaları için hafıza sorunları olacaktır)
- Sam'in yayınladığı tüm kodlar
Bununla birlikte, şu şekilde IEnumerable<T>
adlandırmak için bir uzantı yönteminde kodladığım başka bir geçiş var 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);
}
Orada şaşırtıcı bir şey yok, sadece temel hata kontrolü.
Şuraya taşınıyor 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);
}
Temel olarak, IEnumerator<T>
her öğeyi ve manuel olarak yineler. Şu anda numaralandırılacak herhangi bir öğe olup olmadığını kontrol eder. Her yığın numaralandırıldıktan sonra, herhangi bir öğe kalmazsa, parçalanır.
Sekansta öğeler olduğunu tespit ettikten sonra, iç IEnumerable<T>
uygulamanın sorumluluğunu 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());
}
Yana MoveNext
zaten çağrıldı IEnumerator<T>
geçirilen ChunkSequence
bu tarafından döndürülen öğe verir Current
daha dönmek asla emin yapma ve sonra sayısı artar chunkSize
öğeleri ve her yineleme sonra sırayla sonraki öğeye hareket (ama numarası eğer kısa devre elde edilen öğeler yığın boyutunu aşıyor).
Kalan öğe yoksa, InternalChunk
yöntem dış döngüde başka bir geçiş yapar, ancak MoveNext
ikinci kez çağrıldığında , dokümantasyona göre hala vurgulanır (vurgu mayın):
MoveNext koleksiyonun sonunu geçerse, numaralandırıcı koleksiyondaki son öğeden sonra konumlandırılır ve MoveNext false değerini döndürür. Numaralandırıcı bu konumda olduğunda, MoveNext'e yapılan sonraki çağrılar da Sıfırla çağrılıncaya kadar false değerini döndürür.
Bu noktada, döngü kırılacak ve dizilerin sırası sona erecektir.
Bu basit bir testtir:
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();
}
}
Çıktı:
Group: 1 - a, g, e,
Group: 2 - w, p, s,
Group: 3 - q, f, x,
Group: 4 - y, i, m,
Group: 5 - c,
Önemli bir not, bu olacak değil Üst dizisindeki herhangi bir noktada tüm çocuk sırayı veya mola tahliye yoksa çalışır. Bu önemli bir uyarıdır, ancak kullanım durumunuz her sekans dizisinin elemanını için işe yarayacaktır.
Ek olarak, Sam'in bir noktada yaptığı gibi, siparişle oynarsanız garip şeyler yapar .