Snippets

Stefan Glienke Batch Iterator

Created by Stefan Glienke last modified
program BatchIterator;

{$APPTYPE CONSOLE}

uses
  Spring.Collections,
  Spring.Collections.Base;

type
  TBatchIterator<T> = class(TIterator<IEnumerable<T>>)
  private
    fSource: IEnumerable<T>;
    fSize: Integer;
    fEnumerator: IEnumerator<T>;
  protected
    function Clone: TIterator<IEnumerable<T>>; override;
  public
    constructor Create(const source: IEnumerable<T>; size: Integer);

    function MoveNext: Boolean; override;
  end;

  TEnumerableHelper = class helper for TEnumerable
    class function Batch<T>(const source: IEnumerable<T>; size: Integer): IEnumerable<IEnumerable<T>>; static;
  end;

{ TBatchIterator<T> }

constructor TBatchIterator<T>.Create(const source: IEnumerable<T>;
  size: Integer);
begin
  inherited Create;
  fSource := source;
  fSize := size;
end;

function TBatchIterator<T>.Clone: TIterator<IEnumerable<T>>;
begin
  Result := TBatchIterator<T>.Create(fSource, fSize);
end;

function TBatchIterator<T>.MoveNext: Boolean;
var
  count: Integer;
  bucket: TArray<T>;
begin
  Result := False;

  if fState = STATE_ENUMERATOR then
  begin
    fEnumerator := fSource.GetEnumerator;
    fState := STATE_RUNNING;
  end;

  if fState = STATE_RUNNING then
  begin
    count := 0;
    while (count < fSize) and fEnumerator.MoveNext do
    begin
      if not Assigned(bucket) then
        SetLength(bucket, fSize);

      bucket[count] := fEnumerator.Current;
      Inc(count);
    end;

    if Assigned(bucket) and (count > 0) then
    begin
      if count < fSize then
        SetLength(bucket, count);
      fCurrent := TEnumerable.Query<T>(bucket);
      Exit(True);
    end;
  end;
end;

{ TEnumerableHelper }

class function TEnumerableHelper.Batch<T>(const source: IEnumerable<T>;
  size: Integer): IEnumerable<IEnumerable<T>>;
begin
  Result := TBatchIterator<T>.Create(source, size);
end;

var
  batches: IEnumerable<IEnumerable<Integer>>;
  e: IEnumerable<Integer>;
  i: Integer;
begin
  batches := TEnumerable.Batch<Integer>(TEnumerable.Range(1, 1500), 1000);
  for e in batches do
  begin
    for i in e do
      Write(i, ' ');
    Writeln;
  end;

  Readln;
end.

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.