Easiest way to find the mean of a dynamic array - delphi

I have created a dynamic array, and have passed values to it. Is there a shortcut for finding mean of dynamic array.
var
TheMin, TheMax: Integer;
x: array of Integer; //Dynamic array declaration
....
TheMin := MinIntValue(x);//I am able to retrieve the minium value of the dynamic array
TheMax := MaxIntValue(x);//I am able to retrieve the maximum value of the dynamic array
Is there a other way to get mean using Math library.

It is very easy to write such a function.
function Mean(const Data: array of Integer): Double; overload;
var
i: Integer;
begin
Result := 0.0;
for i := low(Data) to high(Data) do
Result := Result + Data[i];
Result := Result / Length(Data);
end;
I overloaded this so that it could sit alongside the same named functions in the Math unit.
If you wish to use built in library code you can use SumInt from the Math unit:
TheMean := SumInt(x) / Length(x);
SumInt performs the summation using an Integer accumulator. This is probably faster than the bespoke function that uses a floating point accumulator. However, an Integer accumulator is potentially subject to overflow which may be off-putting. On the other hand, an Integer accumulator is potentially more accurate than a floating point accumulator. Depending on your usage requirements these issues may be important to you.
In bother cases, if the input array is of length zero a runtime floating point divide by zero error will be raised.

If the array has additions or deletions, recalculating the average from scratch can get rather time consuming.
In that case it may be worthwhile to calculate a running average instead.
function RecalcAverage(OldAverage: double; const OldArray, Additions, Deletions: TIntArray): double; overload;
var
i: integer;
begin
i:= Length(OldArray) + Length(Additions) - Length(Deletions);
WeighingFactor := 1 / i;
Result:= OldAverage;
for i:= 0 to Length(Deletions) -1 do begin
Result:= Result - (Deletions[i] * WeighingFactor);
end;
for i:= 0 to Length(Additions) -1 do begin
Result:= Result + (Additions[i] * WeighingFactor);
end;
end;
If you have a running sum handy, you can avoid the rounding errors and calculate an exact average.
function RecalcAverage(var RunningTotal: Int64; const OldArray, Additions, Deletions: TIntArray): double; overload;
var
i: integer;
begin
for i:= 0 to Length(Deletions) -1 do begin
RunningTotal:= RunningTotal - Deletions[i];
end;
for i:= 0 to Length(Additions) -1 do begin
RunningTotal:= RunningTotal + Additions[i];
end;
Result:= RunningTotal / (Length(OldArray) + Length(Additions) - Length(Deletions));
end;
If performance is an issue, it would make much more sense to calculate all the needed values in a single loop.
type
TStats = record
MaxVal: integer;
MinVal: integer;
Average: double;
end;
function CalcStats(const input: TIntArray): TStats;
var
MinVal, MaxVal: integer;
Total: Int64;
i: integer;
begin
Assert(Length(input) > 0);
MinVal:= input[0];
MaxVal:= MinVal;
Total:= MinVal;
for i:= 1 to Length(input) -1 do begin
MinVal:= Min(MinVal, input[i]);
MaxVal:= Max(MinVal, input[i]);
Total:= Total + input[i];
end;
Result.MinVal:= MinVal;
Result.MaxVal:= MaxVal;
Result.Average:= Total / Length(input);
end;

Related

How do I split any number into its parts?

I have used this code to split into parts
How to find the numbers in the thousands, hundreds, tens, and ones place in DELPHI for an input number? For example: 155 has 5 ones, 5 tens, etc
however I now need to handle floats.
eg. 101.01
type TSplitNumber = record
Hundreds : integer
Tens : integer
Ones : integer
DecimalPl1 : integer //this will contain 0
DecimalPl2 : integer //this will contain 1
DecimalPl3 : integer
end;
Heres is implementation so far but it only handles non-floats.
type TDivisions = record
Hundreds : integer;
Tens : integer;
Ones : integer;
end;
function SplitNumberIntoDivisions(number : integer) : TDivisions;
var
p : integer;
Ones : integer;
Tens : integer;
Hundreds : integer;
MyDivision : TDivisions;
begin
p := 1;
while number <> 0 do
begin
if p = 1 then
begin
MyDivision.Ones := (number mod 10);
number := number div 10;
Inc(p);
end;
if p = 2 then
begin
MyDivision.Tens := (number mod 10);
number := number div 10;
Inc(p);
end;
if p = 3 then
begin
MyDivision.Hundreds := (number mod 10);
number := number div 10;
Inc(p);
end;
Result := MyDivision;
end;
end;
Anyone got any idea on how to do this?
Ben
First of all, recognise what your float is. Depending on the architecture you will have a certain number of significant digits. Upto 15 is typical but certain architectures may (at some point) give you more, and BCD as implemented in the RTL will give you up to 64.
You then have a 'power' indicating where the decimal point is. Typically you refer to the parts of the float as the mantissa and exponent.
So your answer is going to comprise a set of dgits, each digit being a power of 10, where the powers of 10 are all consecutive and may be all >0 or all <0 or they could straddle 0.
So you will need a structure to hold your powers of 10 which could be something like:
type TDecimalFactor = class(TObject)
Digit: Integer;
Power: Integer;
end;
You can find out what your largest power of 10 is by taking the base 10 log of the number. (So log(100) is 2 and log(1000) is 3 and log(0.1) is -1).
I suggest it would probably be fairly straightforward to 'normalise' your number by dividing it by the highest power - so you have a number which is between 1 and 9.999999999999999 and you know the power it represents. Then work through the number for a many digits as you want (bearing in mind the resolution of the platform) multiplying the float by 10 each time and decrementing your power by 1.
Sample program for you to play with:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Math, System.Generics.Collections;
type
TDecimalFactor = class(TObject)
protected
_nDigit: Integer;
_nPower: Integer;
function _GetValue(): Double;
public
constructor Create(nDigit, nPower: Integer);
procedure ShowFactor();
property Digit: Integer read _nDigit;
property Power: Integer read _nPower;
property Value: Double read _GetValue;
end;
TDecimalFactors = class(TObjectList<TDecimalFactor>)
protected
function _GetValue(): Double;
public
property Value: Double read _GetValue;
end;
constructor TDecimalFactor.Create(nDigit, nPower: Integer);
begin
Self._nDigit:=nDigit;
Self._nPower:=nPower;
inherited Create();
end;
function TDecimalFactor._GetValue(): Double;
begin
Result:=Self._nDigit*System.Math.Power(10, Self._nPower);
end;
procedure TDecimalFactor.ShowFactor();
begin
writeln('Factor: ', IntToStr(Self._nDigit), ' x ', FloatToStr(System.Math.Power( 10, Self._nPower)));
end;
function TDecimalFactors._GetValue(): Double;
var
pFactor: TDecimalFactor;
begin
Result:=0;
for pFactor in Self do
Result:=Result+pFactor.Value;
end;
var
fValue: Double;
fLog: Double;
nPower: Integer;
fPower: Double;
nDigits: Integer;
nLoop: Integer;
pDigits: TDecimalFactors;
pFactor: TDecimalFactor;
begin
try
pDigits:=TDecimalFactors.Create(true);
fValue:=6.5788902E-5; // try different values here to test operation
writeln('Input Value: '+FloatToStr(fValue));
nDigits:=15;
fLog:=log10(fValue);
nPower:=floor(fLog);
fPower:=Power(10,nPower);
fValue:=fValue/fPower;
nLoop:=0;
while(nLoop<nDigits) do
begin
pFactor:=TDecimalFactor.Create(floor(fValue), nPower);
pDigits.Add(pFactor);
pFactor.ShowFactor();
fValue:=(fValue-pFactor.Digit)*10;
inc(nLoop);
dec(nPower);
// stop the loop when we have got far enough, recognising limited precision
if(SameValue(fValue, 0, 0.00000001)) then
break;
end;
writeln('Factorised Value: '+FloatToStr(pDigits.Value));
FreeAndNil(pDigits);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

How to shift data in array?

///Example
some_array[0]:=0;
some_array[1]:=1;
some_array[2]:=2;
some_array[3]:=3;
some_array[4]:=4;
And now I need to shift values in array like this (by one cell up)
some_array[0]:=1;
some_array[1]:=2;
some_array[2]:=3;
some_array[3]:=4;
some_array[4]:=0;
Is there any build in procedure or I have to do this manually by copying to some temporary array?
There is no built in function for this. You will need to write your own. It might look like this:
procedure ShiftArrayLeft(var arr: array of Integer);
var
i: Integer;
tmp: Integer;
begin
if Length(arr) < 2 then
exit;
tmp := arr[0];
for i := 0 to high(arr) - 1 do
arr[i] := arr[i + 1];
arr[high(arr)] := tmp;
end;
Note that there is no need to copy to a temporary array. You only need to make a temporary copy of one element.
If your arrays are huge then the copying overhead could be significant. In which case you would be better off using a circular array. With a circular array you remember the index of the first element. Then the shift operation is just a simple increment or decrement operation on that index, modulo the length of the array.
If you use a modern Delphi then this could readily be converted to a generic method. And I think it should be easy enough for you to write the shift in the opposite direction.
There is no such procedure in the RTL.
A generic procedure (as proposed by #DavidHeffernan) might look something like this:
Type
TMyArray = record
class procedure RotateLeft<T>(var a: TArray<T>); static;
end;
class procedure TMyArray.RotateLeft<T>(var a: TArray<T>);
var
tmp : T;
i : Integer;
begin
if Length(a) > 1 then begin
tmp := a[0];
for i := 1 to High(a) do
a[i-1] := a[i];
a[High(a)] := tmp;
end;
end;
var
a: TArray<Integer>;
i:Integer;
begin
SetLength(a,5);
for i := 0 to High(a) do a[i] := i;
TMyArray.RotateLeft<Integer>(a);
for i := 0 to High(a) do WriteLn(a[i]);
ReadLn;
end.
A low level routine using Move() could be used if performance is critical:
class procedure TMyArray.RotateLeft<T>(var a: TArray<T>);
var
tmp : T;
begin
if Length(a) > 1 then begin
Move(a[0],tmp,SizeOf(T)); // Temporary store the first element
Move(a[1],a[0],High(a)*SizeOf(T));
Move(tmp,a[High(a)],SizeOf(T)); // Put first element last
// Clear tmp to avoid ref count drop when tmp goes out of scope
FillChar(tmp,SizeOf(T),#0);
end;
end;
Note the FillChar() call to clear the temporary variable at the end. If T is a managed type, it would otherwise drop the reference count of the last array element when going out of scope.
Stumbling across this one while facing a similar issue.
I have not implemented it yet, but have thought about this different approach: KEEP the array as it is, but make a new procedure to read values where you change the "zero" position.
Example:
read_array(index: integer; shift: integer)..
So if your original array is read with this function, using shift "1" it would read "1,2,3,4,0" (obviously looping). It would require you to keep track of a few things, but would not require modifying anything. So performance should be greater for very large arrays.
Similar would work for other types as well.
EDIT: an example function with free start index and variable step size plus sample size is here:
function get_shifted_array(inArray: TStringList; startindex,
lineCount: integer;
stepsize: integer): TStringList;
var
i : integer; // temp counter
nextindex : integer; // calculate where to get next value from...
arraypos : integer; // position in inarray to take
temp : tstringlist;
// function to mimic excel Remainder( A,B) function
// in this remainder(-2,10) = 8
//
function modPositive( dividend, divisor: integer): integer;
var
temp : integer;
begin
if dividend < 0 then
begin
temp := abs(dividend) mod divisor; // 1 mod 10 =9 for -1
// 122 mod 10 = 2 for -122
result := (divisor - temp);
end
else
result := dividend mod divisor;
end;
begin
nextindex := startindex; // where in input array to get info from
temp := tstringlist.create; // output placeholder
for i := 1 to lineCount do
begin
// convert to actual index inside loop
arraypos := modPositive(nextindex, inarray.count); // handle it like Excel: remainder(-1,10) = 9
// if mod is zero, we get array.count back. Need zero index then.
if arraypos = inArray.Count then arraypos := 0; // for negative loops.
// get the value at array position
temp.Add( 'IDX=' + inttostr(arraypos) + ' V=' + inarray[ arraypos ] );
// where to go next
// should we loop ?
if ((nextindex+ stepsize +1)> inArray.Count ) then
begin
nextindex := (nextindex + stepsize ) mod inArray.Count;
end
else
nextindex := nextindex + stepsize;
end;
result := temp;
end;
Thereby:
get_shifted_array(
inputarray,
-1, // shiftindex
length(inputarray),
1 ) // stepsize
would return the array shifted backwards one place.
All without any modification to array.

Find the Maximum in a List of calculated values using the Parallel Programming Library

I have a list of values. I'd like to find the maximum value. This is a common task. A simple version might be:
iBest := -1;
iMax := -1e20;
for i := 0 to List.Count - 1 do
begin
if List[i].Value > iMax then
begin
iBest := i;
iMax := List[i].Value;
end;
end;
In my case, the .Value getter is the performance bottleneck as it invokes a time consuming calculation (~100ms) which returns the final value.
How can I make this parallel using the Parallel Programming Library?
If the value is a calculated value and you can afford to cache, a simple solution might look something like this:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, Threading, DateUtils, Math, Generics.Collections, StrUtils;
type
TFoo = class
private
FCachedValue : double;
function GetValue : double;
public
property CalculateValue : double read GetValue;
property CachedValue : double read FCachedValue;
end;
TFooList = class(TObjectList<TFoo>)
public
procedure CalculateValues;
function GetMaxValue(var BestIndex : integer) : double;
end;
function TFoo.GetValue : double;
begin
sleep(10); // simulate taking some time... make up a value
FCachedValue := DateUtils.MilliSecondOfTheSecond(now);
result := FCachedValue;
end;
procedure TFooList.CalculateValues;
begin
TParallel.For(0, Count - 1,
procedure (j:integer)
begin
self[j].CalculateValue;
end);
end;
function TFooList.GetMaxValue(var BestIndex : Integer) : double;
var
i, iBest : integer;
maxval : double;
begin
CalculateValues;
iBest := 0;
maxval := self[0].CachedValue;
for i := 0 to self.Count - 1 do
begin
if self[i].CachedValue > maxval then
begin
iBest := i;
maxval := self[i].CachedValue;
end;
end;
BestIndex := iBest;
result := maxval;
end;
var
LFooList : TFooList;
i, iBest : integer;
maxval : double;
begin
LFooList := TFooList.Create(true);
try
for i := 0 to 9999 do LFooList.Add(TFoo.Create);
maxval := LFooList.GetMaxValue(iBest);
WriteLn(Format('Max value index %d', [iBest]));
WriteLn(Format('Max value %.6f', [maxval]));
finally
LFooList.Free;
end;
ReadLn;
end.
This way your object retains a cache of the last calculated value, which you can refresh at any time, but which you can also access quickly. It's somewhat easier to parallelize a full calculation of the list than it is to paralellize the min/max search, and if the bottleneck is the calculation then it makes sense to restrict the added complexity to that operation alone (where you know the overhead is worth it).

How to concat multiple strings with Move?

How can I concat an array of strings with Move. I tried this but I just cannot figure how to get Move operation working correctly.
program Project2;
{$POINTERMATH ON}
procedure Concat(var S: String; const A: Array of String);
var
I, J: Integer;
Len: Integer;
begin
Len := 0;
for I := 0 to High(A) do
Len := Len + Length(A[I]);
SetLength(S, Length(S) + Len);
for I := 0 to High(A) do
Move(PWideChar(A[I])[0], S[High(S)], Length(A[I]) * SizeOf(WideChar));
end;
var
S: String;
begin
S := 'test';
Concat(S, ['test', 'test2', 'test3']);
end.
I'd write this function like so:
procedure Concat(var Dest: string; const Source: array of string);
var
i: Integer;
OriginalDestLen: Integer;
SourceLen: Integer;
TotalSourceLen: Integer;
DestPtr: PChar;
begin
TotalSourceLen := 0;
OriginalDestLen := Length(Dest);
for i := low(Source) to high(Source) do begin
inc(TotalSourceLen, Length(Source[i]));
end;
SetLength(Dest, OriginalDestLen + TotalSourceLen);
DestPtr := PChar(Pointer(Dest)) + OriginalDestLen;
for i := low(Source) to high(Source) do begin
SourceLen := Length(Source[i]);
Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char));
inc(DestPtr, SourceLen);
end;
end;
It's fairly self-explanatory. The complications are caused by empty strings. Any attempt to index characters of an empty string will lead to exceptions when range checking is enabled.
To handle that complication, you can add if tests for the case where one of the strings involved in the Move call is empty. I prefer a different approach. I'd rather cast the string variable to be a pointer. That bypasses range checking but also allows the if statement to be omitted.
Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char));
One might wonder what happens if Source[i] is empty. In that case Pointer(Source[i]) is nil and you might expect an access violation. In fact, there is no error because the length of the move as specified by the third argument is zero, and the nil pointer is never actually de-referenced.
The other line of note is here:
DestPtr := PChar(Pointer(Dest)) + OriginalDestLen;
We use PChar(Pointer(Dest)) rather than PChar(Dest). The latter invokes code to check whether or not Dest is empty, and if so yields a pointer to a single null-terminator. We want to avoid executing that code, and obtain the address held in Dest directly, even if it is nil.
In the second loop you forget that S already has the right size to get filled with all the elements so you have to use another variable to know the destination parameter of Move
procedure Concat(var S: String; const A: Array of String);
var
I, Len, Sum: Integer;
begin
Len := 0;
for I := 0 to High(A) do
Inc(Len, Length(A[I]));
Sum := Length(S);
SetLength(S, Sum + Len);
for I := 0 to High(A) do
begin
if Length(A[I]) > 0 then
Move(A[I][1], S[Sum+1], Length(A[I]) * SizeOf(Char));
Inc(Sum, Length(A[I]));
end;
end;
Casting the source parameter to PWideChar is totally superfluous since the Move function use a kind of old generic syntax that allows to pass everything you want (const Parameter without type).

Remove same element array in delphi

I'm trying to remove the same element of array in delphi.
For examples :
R[1] := 33332111111111111111111111323333333334378777433333344333333333277
I want to make it become 32132343787434327. and saved in the new array.
Could you give some idea?
I already tried to make each of R[1] element to Array. And tried some code.
for i:=1 to length(NR) do
begin
found:=false;
for k:=i+1 to length(NR) do
begin
if (NR[i]=NR[k]) then
begin
found:=true;
end;
end;
if (not found) then
begin
Memo1.Lines.Add(NR[i]);
end;
end;
But the result is 184327.
could you guys help me? thanks a lot. I'm so desperate to do this.
You appear to be working with strings rather than arrays. In which case you need this function:
function RemoveAdjacentDuplicates(const X: string): string;
var
i, j: Integer;
begin
SetLength(Result, Length(X));
j := 0;
for i := 1 to Length(Result) do
if (i=1) or (X[i]<>X[i-1]) then
begin
inc(j);
Result[j] := X[i];
end;
SetLength(Result, j);
end;
Let's work through this.
First of all I allocate the result variable. This is likely to be an over allocation. We know that the result cannot be larger than the input.
We use two indexing local variables, the rather weakly named i and j. We could give them descriptive names but for such a short function one might decide that it was not necessary. Do feel free to come up with other names if you prefer. You might choose idxIn and idxOut for instance.
One variable indexes the input, the other indexes the output. The input index is used in a simple for loop. The output index is incremented every time we find a unique item.
The if condition tests whether the input index refers to a character that differs from the previous one. The first element has no previous element so we always include it.
Once the loop completes we know how long the output is and can perform the final allocation.
Adapting this for an array is simple. You just need to account for arrays using zero-based indexes. For a bit of fun, here's a generic version for arrays:
type
TMyArrayHelper = class
class function RemoveAdjacentDuplicates<T>(const X: array of T): TArray<T>;
static;
end;
class function TMyArrayHelper.RemoveAdjacentDuplicates<T>
(const X: array of T): TArray<T>;
var
i, j: Integer;
Comparer: IEqualityComparer<T>;
begin
Comparer := TEqualityComparer<T>.Default;
SetLength(Result, Length(X));
j := 0;
for i := 0 to high(Result) do
if (i=0) or not Comparer.Equals(X[i], X[i-1]) then
begin
Result[j] := X[i];
inc(j);
end;
SetLength(Result, j);
end;
Note the subtly different placement of inc(j). This is necessitated by the switch to zero-based indexing.
A slightly more complex alternative with fewer tests would be:
class function TMyArrayHelper.RemoveAdjacentDuplicates<T>
(const X: array of T): TArray<T>;
var
i, j, len: Integer;
Comparer: IEqualityComparer<T>;
begin
Comparer := TEqualityComparer<T>.Default;
len := Length(X);
SetLength(Result, len);
if len=0 then
exit;
Result[0] := X[0];
j := 1;
for i := 1 to len-1 do
if not Comparer.Equals(X[i], X[i-1]) then
begin
Result[j] := X[i];
inc(j);
end;
SetLength(Result, j);
end;

Resources