Is there anything I can do to reduce the runtime of this program? - loops

uses sysutils;
var
stringlength,querynum,i,start,tail,j,cnt:int64;
input,temp:ansistring;
querychar:char;
begin
readln(stringlength,querynum);
readln(input);
for i:=1 to querynum do begin
readln(querychar,start,tail);
temp:=copy(input,start,tail-start+1);
writeln(temp.CountChar(querychar));
end;
end.
This is a program for finding how many times a character occurs during a certain segment of a string. The input format is first line input the length of the string and the number of queries(n), then the next n lines are input the character to search for its occurence, and the section of the string (eg from 3 to 8). Sometimes the runtime for the program is very high, which I think is due to the for loop. Is there any way I could reduce the runtime?

Speed usually goes at the expense of memory.
If you want to gain speed, you can transform your data into a form/layout that can be even faster processed than the input.
In particular sets are suitable to achieve your goal.
Now, this is an implementation detail.
Pascal – the programming language – does not prescribe any memory layout.
Unlikely as it may be, your processor could theoretically produce even worse results when using a set.
I therefore generally recommend using the most maintainable algorithm.
Your algorithm already satisfies this criterion quite well.
program characterSubstringOccurrences(input, output);
type
{ `integer`-prefix to facilitate sorting in documentation tools. }
integerNonNegative = 0..maxInt;
{
Performs specified number of character queries on sample.
\param sample the sample to inspect for a certain character
\param queryCount the total number of queries to prompt
}
procedure processQueries(
protected sample: string;
queryCount: integerNonNegative
);
type
sampleIndex = 1..sample.capacity;
sampleIndices = set of sampleIndex;
var
c: char;
i, j: sampleIndex;
characterIndex: array[char] of sampleIndices value [otherwise []];
This is a subroutine, because it trivializes the creation of sets with non-constant bounds (here the capacity of the given sample).
We simply need to declare our data types accordingly; no invocation of new necessary.
begin
{ --- analyze `sample` step --- }
for i := 1 to length(sample) do
begin
characterIndex[sample[i]] := characterIndex[sample[i]] + [i];
end;
{ --- draw conclusions from analysis step --- }
for queryCount := 1 to queryCount do
begin
readLn(c, i, j);
writeLn(card(characterIndex[c] * [i..j]));
end;
end;
Evidently this avoids re-inspecting the sample over and over again.
All you need to do is taking the cardinality of the intersection of [start, tail] with the set of indices specified character appears at.
{ === MAIN ================================================== }
var
sample: ^string;
sampleLength: integerNonNegative;
queryCount: integerNonNegative;
begin
if EOF then
begin
writeLn('Error: Program needs input.');
halt;
end;
read(sampleLength);
if sampleLength = 0 then
begin
writeLn('Error: Sample length must be positive.');
halt;
end;
new(sample, sampleLength);
readLn(queryCount);
readLn(sample^);
if queryCount > 0 then
begin
processQueries(sample^, queryCount);
end;
end.
Now this is a program compliant to ISO standard 10206 “Extended Pascal”.
From your code’s non-standard deviations I gather you’re using some dialect, yet the general idea of extracting/transforming data into a form that’s faster to process remains.

Related

How can I set big array size in pascal?

I need to create an array in pascal with an enormous size, is such thing possible ?
I know the size number, I mean it's not n or unknown, it's just a really really big number:
2 ^ 255
Can I do that or not ? and if not is there any other way I can make something like that happen ?
Thanks in advance
Update:
The peoblem I'm trying to solve is, by giving a number between 1 to 255 (including 1 & 255), I need to print all Gray Code with length of that number, for example:
giving n=2 the program should print:
00, 01, 11, 10
since I have the max number of size that I can enter I assumed I'd make an array with the max number, the thing is maybe I can solve this with recursion, but I;m very new to pascal so I don't know how can I do that (at least not yet)
here's what I meant:
type arr = array[1..255,1..MAXINT] of integer;
hints and tips can be very helpful <3
I guess it is an XY problem. Is seems useless to store such a big ammount of data in an array instead of fetching it on demand.
Here are the reasons:
The supposed array must be populated programmatically (a human being is unable to populate such an array manually) and this means you definitely have an algorithm for that purpose.
How will you allocate 10^64 GB (calculated by #Alex-K) of memory to store all this data?
Windows 7/8 Ultimate x64 has a maximum RAM limit of 192 GB and 512 GB respectively (for x32 - 4 GB only).
How much time you think it will take to initialize this array and assign values to its memebers?
Conclusion:
Why not to use a function Foo(const bt:byte; const it: cardinal): integer; intended to populate the array for the purpose of fetching the necessary values? You will fetch the data from something like Foo(100 ,32000) instead of MyArray[100, 32000].
If you have some exclusions (values that are different from those calculated by Foo changed at runtime by your user) you can ever store them in an array of TMyRec (or TList) where TMyRec = record Val: integer; Bt: byte; It: cardinal; end;.
I am not proficient in pascal but here is something I have written. It takes a numeric input and converts it in binary then into gray code.
This is the best I could do as again Pascal is not my main lang of work. :)
Uses Math;
var
a,b,d,e,f:integer;
c:array[1..255] of integer;
begin
write('input a decimal number! ');
readln(a);
write('grey code of decimal ',a,' is ');
if a<=1 then write(a) else
repeat
b:=b+1;
d:=a div 2;
c[b]:=a mod 2;
if d<=1 then
begin
b:=b+1;
c[b]:=d;
end;
a:=d;
until d<=1;
for e:=b downto 1 do
begin
//HERE YOU WOULD NEED TO EDIT AND FIX THIS, I THINK THIS WILL ONLY WORK FOR
//1-9
write(c[e -1] xor 1 shl (c[e]>>1));
end;
readln
end.

Parsing a text in Delphi

I have a textfile that has the following data:
dgm P1
s0:->b1
*s1:b2->b1
S2:b2->b1,b3
dgm P2
s0:->b2
*s1:b1,b3->b2
I want to parse this file to get an array whose element will contain each of the
dgm's till the next one. That is, the first element will be:
dgm P1
s0:->b1
*s1:b2->b1
S2:b2->b1,b3
The second element will be:
dgm P2
s0:->b2
*s1:b1,b3->b2
etc.
Please how do i go about that in Delphi. I am looking for a better way to do this. I tried loading from the file to TStringList.
begin
str:=TstringList.Create;
try
str.LoadFromFile('example.txt');
for i:=0 to str.Count -1 do
if str[i] ='dgm' then
//get the position, add it to an array;
//get the next position, till the end;
//use the positions to divide up the string
finally
str.Free;
However, this is not working and I also think there might be a better way
to handle this than I briefly outlined.
AS. This answer uses features of Delphi 2010+ because it was written before the topicstarter specified his target Delphi version. Still this code can be the skeleton for his own implementation using libraries and language features he has available.
function ParseDgmStringsList( const str: TStrings ): TArray<TArray<String>>;
var
s: string;
section: TList<String>;
receiver: TList<TArray<String>>;
procedure FlushSection;
begin
if section.Count > 0 then begin
receiver.Add( section.ToArray() );
section.Clear;
end;
end;
begin
section := nil;
receiver := TList<TArray<String>>.Create;
try
section := TList<String>.Create;
for s in str do begin
if StartsText('dgm ', s) then // or StartsStr
FlushSection;
section.Add( s );
end;
FlushSection;
Result := receiver.ToArray();
finally
receiver.Destroy;
section.Free;
end;
end;
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.StrUtils.StartsStr
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.StrUtils.StartsText
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.Generics.Collections.TList_Properties
PS. Note that "using AnsiContainsStr(str,'dgm')" is fragile and hardly correct - it will generate false positive at lines like S2:b2->bcdgmaz,b3.
You should check that dgm starts the string and that it is a separate word rather than part of some random longer word (in other words search for 'dgm' + #32 instead of mere 'dgm'
PPS. Another thing to consider is how would you handle files that starts with non-dgm lines? What would you do with empty lines, indented lines? For example how would you parse the file like that?
s8:->b2
;*s1:b1,b3->b2
dgm P1
s0:->b1
*s1:b2->b1
S2:b2->b1,b3
dgm P2
s0:->b2
*s1:b1,b3->b2

Arrays in Delphi (object Pascal) using variables?

I have these 10 numbers (one in each line) in a Text File and I need them to be sorted in a chronological order starting with the highest number. I wrote a code which works just fine, but the problem is that the code isn't flexible, because once I add another number to the Text File it won't work since the code is set to sort 10 numbers only...this is due to my array of integers which is supposed to read the values before the sorting process starts, but won't allow me to add a variable to the array's properties so it will be able to read and sort any-size text file...I know there has to be a way of making a program which can sort any-size file of this structure, just please tell me how I could improve my code. (If you think my way isn't too efficient, it's because that's my homework from high school and I need to use these arrays to implement a bubblesort).
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
numbers, sortednumbers : TextFile;
count : integer=0;
number : array[1..10] of integer;
I : integer;
Procedure Swap(var X, Y : Integer);
var
Temp : integer;
begin
Temp := X;
X := Y;
Y := Temp;
end;
procedure Assign;
var I : Integer;
begin
reset(numbers);
for I := 1 to count do ReadLn(numbers, number[I]);
end;
procedure BubbleSort;
var I, J : integer;
begin
for I := 2 to count do
begin
for J := count downto I do
if (number[J] > number[J - 1]) then
Swap(number[J - 1], number[J]);
end;
end;
begin
AssignFile(numbers, 'Numbers.txt');
AssignFile(sortednumbers, 'Sorted-Numbers.txt');
Reset(numbers);
While not EoF(numbers) do
begin
ReadLn(numbers);
Inc(count);
end;
Reset(numbers);
ReWrite(sortednumbers);
Assign;
BubbleSort;
For I := 1 to count do writeln(sortednumbers, number[I]);
CloseFile(numbers);
CloseFile(sortednumbers);
end.
Use a dynamic array. This is an array that can change the number of elements it holds.
Instead of declaring:
number : array[1..10] of integer;
instead skip the bounds declaration:
Number : array of integer;
Then, before you start using it, set its length:
SetLength(Number, 10);
Once you are done, free the memory by setting it to have length 0:
SetLength(Number, 0);
Note that:
Indexes of a dynamic array start from 0, not 1. That is, Number[0] is the first element and Number[9] is the tenth. This is quite common in programming but can be confusing if it's not something you've come across before.
There are other 'quality' changes you can make to your code too. As commenter David Heffernan said, stop using global variables. I would also suggest using try/finally for resource allocation and cleanup, and using streams (and another link, wrap this over TFileStream) instead of the old-style file IO you're currently doing. Also, consider your variable names - Number for an array of numbers is odd - why not add the S and call it Numbers, for example?
That might be a bit much all at once, so go slowly in small steps, save and backup often (preferably into source control), and have fun!
And if it had not been a school project:
function Comparer(List: TStringList; index1, index2: integer): integer;
begin
try
Result:= StrToInt(List[index1]) - StrToInt(List[Index2]);
except
raise Exception.Create('Your file does not contain numbers');
end;
end;
function SortNumbers
var
lStringList: TStringlist;
begin
lStringList := TStringlist.create;
try
lStringList.LoadFromFile('Numbers.txt');
lStringList.CustomSort(Comparer);
lStringList.SaveToFile('Sorted-Numbers.txt');
finally
lStringList.Free;
end;
end;
However the Delphi RTL uses Quicksort, not Bubblesort.

Making new array whose elements are every second element of another array.(Pascal)

I've been trying to make a program that will ask user to input elements of an array and then use that array to make a new one whose elements would be every 2nd element of inputted array. This is what I was writing:
program Keanu;
uses crt;
type Arr=array of integer;
var n,i:integer;
A,C:Arr;
begin
writeln('--Enter desired length of array--');
readln(n);
setlength(A,n);
setlength(C,n);
writeln('Elements of array A:');
for i:=1 to n do
readln(A[i]);
writeln('Elements of array C are:');
i:=1;
while (i<=n) do
begin
c[i]:=a[i];
i:=i+2;
end;
write('C = {');
for i:=1 to n do
begin
if c[i]=0 then continue else
begin
write(c[i],' ');
end;
end;
write('}');
readln;
end.
But as you can notice this is far from efficient way to make this program do the job.
First, because my new array will contain blank/empty elements(zeros) which I simply ignored with continue statement and I dont want to do that if possible.
Second,I have problem when inputting an even number for array length.Last element of new array in output window is very small,negative number and he shouldn't be there at all.I know this has to do something with my counter "i" crossing into "undefined" indexes of array.
I also tried replacing while loop with some variations of:
for i:=0 to n do
c[i]:=a[2*i-1] ;
Which is more elegant way but I still get , besides desired result , those large numbers , again because of crossing limits of an array.I suspect this has to be done with proper steps of how new array is made and moving those elements next to each other with no blank elements.
So, if anyone can give me some solutions of how to get these loop steps and limits into right order and make efficient,shortest algorithm, and preferably without using while loop if possible ,and definitely without ignoring those blank elements of new array.
Declaring variables by one character A, C: array of integer is a bad practice. The name of variable will tell you about it's type and meaning. (highly recommended)
And read about Hungarian notation, then you'll understand why TArr and arrA instead of Arr and A. Not necessary, but recommended. (also recommended)
As for the second arrC, you can use operator div to make it twice smaller than the first array arrA.
You can also crete a new variable that will be n div 2, in order not to change n div 2 in the whole code (good practice):
nDivided := n div 2;
SetLength(arrA,n);
SetLength(arrC, nDivided);
This will make your program quite a bit efficient: you'll save n - (n div 2) * sizeof(integer) bytes.
Here are both cases (for even and odd N). No "blank elements" and no "very small, negative number in the end of new array(-32768)".
N is 6 N is 5
Elements of array A: Elements of array A:
arrA[1]=1 arrA[1]=1
arrA[2]=2 arrA[2]=2
arrA[3]=3 arrA[3]=3
arrA[4]=4 arrA[4]=4
arrA[5]=5 arrA[5]=5
arrA[6]=6
Elements of array C are: Elements of array C are:
arrC[1]=2 arrC[1]=2
arrC[2]=4 arrC[2]=4
arrC[3]=6
Anyway, here is code (a little changed). Also not very good (efficent) but it does exactly what you need.
program WorkingWithArrays;
uses crt;
type
TArr = Array of Integer;
var
i, n: integer;
arrA, arrC: TArr;
begin
writeln('Enter the length of array:');
readln(n);
SetLength(arrA,n);
SetLength(arrC, n div 2);
writeln('Elements of array A:');
for i:=1 to (n) do begin
arrA[i]:=i;
writeln('#> arrA[',i,']=', arrA[i]);
end;
writeln('Elements of array C are:');
i:=1;
while (i <= n div 2) do
begin
arrC[i]:=arrA[i+i];
i:=i+1;
end;
for i:=0 to (n div 2) do begin
if arrC[i]=0 then continue else begin
writeln('#> arrC[',i,']=', arrC[i]);
end;
end;
readln;
end.
// compiled here: http://www.compileonline.com/compile_pascal_online.php

How to use 'Last attribute on multidimensional arrays in Ada?

I am trying to use the 'Last attribute with a 2D array in Ada, but I can't seem to find the correct syntax to do so.
I know that if I have a 1D array/vector I can use A'last or A'last(n) where n is the nth dimension. But if I do the following
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
end temp;
I get the following compile time error:
Storage_Error stack overflow (or erroneous memory access)
So what am I doing wrong?
I am using GNAT Pro 6.4.1 on Linux.
I'd be very surprised if you got a compile-time Storage_Error on that code.
I've grabbed a copy of your code and modified it as follows; it compiles without error using GNAT (gcc-4.4):
procedure Array_2D is
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
return 42; -- added this
end temp;
begin
null;
end Array_2D;
(Note that I had to add the missing return statement in temp.)
Your syntax for the 'Last attribute (not "command") is correct, but since Ada arrays can have arbitrary lower and upper bounds, it's better to use the 'Range attribute instead:
for i in tempTable'Range(1) loop
for j in tempTable'Range(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
As for the Storage_Error exception, that could easily happen at run time (not compile time) if you call your temp function with a very large value for tempIn. Remember that it has to allocate enough space to hold tempIn**2 Integer objects. Presumably you've also created another UnconstrainedArray_2D object to be passed in as the Table parameter.
It's conceivable that the compiler itself could die with a Storage_Error exception, but I don't see anything in your code that might cause that.
Show us a complete (but small) program that demonstrates the problem you're having, along with the exact (copy-and-pasted) error message. Please distinguish clearly between compile-time and run-time errors.
Your tempTable might have a range of 0..tempIn, but you don't know what range your Table has.. They could be of different length, too.
You would have to check that the length is the same and then use relative indices, like this:
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
if tempTable'Length (1) /= Table'Length (1) or else
tempTable'Length (2) /= Table'Length (2)
then
raise Constraint_Error; -- or something else
end if;
for i in 0 .. tempTable'Length (1) - 1 loop
for j in 0 .. tempTable'Length (2) - 1 loop
tempTable(tempTable'First (1) + i, tempTable'First (2) + j) :=
Table(Table'First (1) + i, Table'First (2) + j);
end loop;
end loop;
end temp;
that way it is ensured that both tables are same length and all indices are valid.
If your tempTable is allowed to be smaller than Table, simply adjust the length check to >. The indices would still be valid.
I don't see an actual value for tempIn set. If the value for tempIn coming into the function temp has not been properly initialized or explicitly set, then the value in tempIn could be anything and probably not something you would like.
I was thinking of a default value. (probably shouldn't post when I am not feeling well :-)

Resources