당신은 할 수 사용하는 쿼리의 번호를 사용 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가 활성화되어 결과 시퀀스에서 다른 작업을 수행 할 수 있습니다.
Sam의 답변에 비추어 볼 때 , 나는 이것을하지 않고 이것을 수행하는 더 쉬운 방법이 있다고 느꼈습니다.
- 목록을 다시 반복합니다 (원래는하지 않았습니다)
- 청크를 해제하기 전에 그룹으로 항목을 구체화 (큰 청크의 경우 메모리 문제가 있음)
- Sam이 게시 한 모든 코드
즉 나는 여기에 확장 메서드에 성문화 한 또 다른 패스,의, 말했다 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두 번째로 호출 되면 문서 (강조 광산)에 따라 여전히 false를 반환합니다 .
MoveNext가 컬렉션의 끝을 통과하면 열거자는 컬렉션의 마지막 요소 뒤에 위치하고 MoveNext는 false를 반환합니다. 열거자가이 위치에있을 때 ResetNext가 호출 될 때까지 MoveNext에 대한 후속 호출도 false를 반환합니다.
이 시점에서 루프가 중단되고 시퀀스 시퀀스가 종료됩니다.
이것은 간단한 테스트입니다.
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,
중요한 점 은 전체 하위 시퀀스를 배수하거나 상위 시퀀스의 어느 시점에서든 중단하지 않으면 작동하지 않습니다. 사용 사례 당신이 소비하는 것입니다 경우에 중요한주의이지만, 모든를 시퀀스 시퀀스의 요소를 이것이 효과가 있습니다.
또한 Sam이 한 시점에서했던 것처럼 주문을 가지고 놀면 이상한 일을 할 것 입니다.