Jump to content
Sign in to follow this  
MarkShark

Encoding an n-dimensional array given dimensions and a list of items.

Recommended Posts

This is going to sound like a homework assignment, but it's actually needed for some ZeosLib code to handle PostgreSQL client library digital array format.  The array information is the following:

 

NDims:  The number of dimensions:   Example: 3

DimArray:  An array of dimension sizes.  Example [1,2,2]

ItemsArray:  An array of data items (say Integer.)  Example: [1,2,3,4]

 

I'm trying to figure out an algorithm to turn the information above into a string that has a format like: {{{1,2},{3,4}}}.  I've got it working for 1 and 2 dimensions, but it seems like I'm brute forcing it when it seems like a more clever approach should be possible.   Any tips, hints, or psuedo-code (or actual code!) appreciated!

Share this post


Link to post
7 hours ago, MarkShark said:

This is going to sound like a homework assignment, but it's actually needed for some ZeosLib code to handle PostgreSQL client library digital array format.  The array information is the following:

 

NDims:  The number of dimensions:   Example: 3

DimArray:  An array of dimension sizes.  Example [1,2,2]

ItemsArray:  An array of data items (say Integer.)  Example: [1,2,3,4]

 

I'm trying to figure out an algorithm to turn the information above into a string that has a format like: {{{1,2},{3,4}}}.  I've got it working for 1 and 2 dimensions, but it seems like I'm brute forcing it when it seems like a more clever approach should be possible.   Any tips, hints, or psuedo-code (or actual code!) appreciated!

unit Unit1;

interface

uses system.Generics.Collections, system.Typinfo, system.sysutils;

type
  TDynamicArrayFormatter<T> = class
  strict private
    FData: TArray<T>;
    FDimensions: TArray<cardinal>;
    FIndices: TArray<cardinal>;
    FType: PTypeInfo;
  strict protected
    procedure AddValue(aBuilder: TStringBuilder);
    function CalcLinearIndex: Integer;
    function GetText: string;
    procedure ProcessDimension(aDimension: Cardinal; aBuilder: TStringBuilder);
  public
    constructor Create(const aDimensions: array of cardinal; const aDataArray:
        TArray<T>);
    class function Execute(const aDimensions: array of cardinal; const aDataArray:
        TArray<T>): string;
  end;

implementation

constructor TDynamicArrayFormatter<T>.Create(const aDimensions: array of
    cardinal; const aDataArray: TArray<T>);
begin
  inherited Create;
  SetLength(FDimensions, Length(aDimensions));
  Move(aDimensions[0], FDimensions[0], Length(FDimensions) * Sizeof(Cardinal));
  FData := aDataArray;
  FType:= TypeInfo(T);
  SetLength(FIndices, Length(FDimensions));
end;

procedure TDynamicArrayFormatter<T>.AddValue(aBuilder: TStringBuilder);
var
  LValue: T;
  N: Integer;
  S: string;
begin
  N:= CalcLinearIndex;
  LValue := FData[N];
  case FType.Kind of
    tkInteger: S:= Pinteger(@LValue)^.ToString;
    tkUnicodeString: S:= PPChar(@LValue)^;
  else
    S:= 'unknown type of T';
  end;
  aBuilder.Append(S);
end;

function TDynamicArrayFormatter<T>.CalcLinearIndex: Integer;
var
  I, N: Integer;
begin
  Result := 0;
  N:= 1;
  for I := High(FDimensions) downto Low(FDimensions) do begin
    Inc(Result, N * Pred(FIndices[I]));
    N := N * FDimensions[I];
  end;
end;

class function TDynamicArrayFormatter<T>.Execute(const aDimensions: array of
    cardinal; const aDataArray: TArray<T>): string;
var
  LInstance: TDynamicArrayFormatter<T>;
begin
  LInstance := TDynamicArrayFormatter<T>.create(aDimensions, aDataArray);
  try
    Result := LInstance.GetText;
  finally
    LInstance.Free;
  end;
end;

function TDynamicArrayFormatter<T>.GetText: string;
var
  LBuilder: TStringBuilder;
begin
  LBuilder := TStringBuilder.Create;
  try
    ProcessDimension(1, LBuilder);
    Result := LBuilder.ToString;
  finally
    LBuilder.Free;
  end;
end;

procedure TDynamicArrayFormatter<T>.ProcessDimension(aDimension: Cardinal;
    aBuilder: TStringBuilder);
var
  I: Cardinal;
  LAddValues: Boolean;
begin
  aBuilder.Append('{');
  LAddValues := integer(aDimension) = Length(FDimensions);
  for I := 1 to FDimensions[Pred(aDimension)] do begin
    FIndices[aDimension-1] := I;
    if LAddValues then begin
      if I > 1 then
        aBuilder.Append(',');
      AddValue(aBuilder);
    end
    else
      ProcessDimension(Succ(aDimension), aBuilder);
  end;
  aBuilder.Append('}');
end;



end.

Usage like

 

var
  S: string;
begin
   S:= TDynamicArrayFormatter<string>.execute([1,2,2], ['one','two','three','four']);
   WriteLn(S);
end;

 

  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×