public static IEnumerable <Partition <TResult> > Split <TSource, TResult>(this IEnumerable <TSource> source, int maxSize, Func <TSource, TResult> selector, Func <TSource, bool> predicate = default) { if (source is null) { throw new ArgumentNullException(paramName: nameof(source)); } else if (maxSize < 1) { throw new ArgumentOutOfRangeException(paramName: nameof(maxSize), message: FormatXResource(locator: typeof(ArgumentOutOfRangeException), subpath: "CanNotLessThanOne")); } else if (selector is null) { throw new ArgumentNullException(paramName: nameof(selector)); } // TResult[] portion; var partitionUpperBound = maxSize - 1; var buffer = new List <TResult>(); var bufferTailIndex = -1; var partitionIndex = -1; foreach (var item in source) { if (bufferTailIndex == partitionUpperBound) { portion = new TResult[maxSize]; buffer.CopyTo(index: 0, array: portion, arrayIndex: 0, count: maxSize); bufferTailIndex = -1; yield return(new Partition <TResult>(elements: ListReadOnlyWrap <TResult> .WrapOrEmpty(list: portion), index: checked (++partitionIndex))); } if (predicate?.Invoke(item) ?? true) { if (buffer.Count > ++bufferTailIndex) { buffer[bufferTailIndex] = selector(item); } else { buffer.Add(selector(item)); } } } if (bufferTailIndex > -1) { portion = new TResult[bufferTailIndex + 1]; buffer.CopyTo(index: 0, array: portion, arrayIndex: 0, count: bufferTailIndex + 1); buffer.Clear(); yield return(new Partition <TResult>(elements: ListReadOnlyWrap <TResult> .WrapOrEmpty(list: portion), index: checked (++partitionIndex))); } else { buffer.Clear(); } }
internal Partition(ListReadOnlyWrap <T> elements, int index) { if (index < 0) { throw new ArgumentOutOfRangeException(paramName: nameof(index)); } else if (elements is null) { throw new ArgumentNullException(paramName: nameof(elements)); } // Index = index; Elements = elements; }