How do I extend these data structures in my word frequency program with LineNo (line the word occurs in) and CurLine (current line)? - permutation

I have the program to print out each word in a file along with its frequency but I am trying to adjust it so that it also outputs which lines the word appears on.
I know I could create a Word_List type with
words: Word_Array; --unique words
Num_Words: Natural := 0; -- How many unique words seen so far
curr_line: Natural := 1;
but I wanted to see if I could execute this without doing that and by adjusting my existing code.
procedure v3 is
type Word is record
wlen: Natural := 45; -- Length of the word
count: Natural := 0; -- Total number of occurrences of this word
s: Unbounded_String;
value: Unbounded_String;
LineNo: Natural := 0;
end record;
type IntArray is array (1 .. 10) of Natural;
type Word_Array is array (Natural range <>) of Word;
--Sorting--
function "+" (S : String) return Unbounded_String renames To_Unbounded_String;
function "+" (S : Natural) return Unbounded_String renames To_Unbounded_String;
function "<" (L, R : Word) return Boolean is
begin
return L.s < R.s;
end "<";
function "=" (L, R : Word) return Boolean is
begin
return L.s = R.s;
end "=";
procedure Sort is new Ada.Containers.Generic_Array_Sort (Natural, Word, Word_Array);
----
num_words : Integer;
procedure get_words(wl: out Word_Array) is
Input : File_Type;
begin
num_words := 0;
Open (File => Input,
Mode => In_File,
Name => "input.txt");
loop
declare
s : String := Get_Line(Input);
found: Boolean := false;
word : Unbounded_String;
index : Integer := 0;
word_len:Integer := 0;
empty : Unbounded_String;
space : Unbounded_String;
begin
-- process the contents of Line here.
index := 1;
for I in s'Range loop
word_len := word_len + 1;
if (index = s'Length or s(I) = ' ') then
if (s(I) /= ' ') then
word := word & s(I);
end if;
space := space & s(I);
found := false;
for i in 1 .. num_words loop
if word = wl(i).s then
wl(i).count := wl(i).count + 1;
found := true;
end if;
exit when found;
end loop;
if not found and word /= empty then -- Add word to list
num_words := num_words + 1;
wl(num_words).s := word;
wl(num_words).wlen := word_len;
wl(num_words).count := 1;
end if;
word := empty;
word_len := 0;
else
word := word & s(I);
end if;
index := index + 1;
end loop;
end;
end loop;
exception
when End_Error =>
if Is_Open(Input) then
Close (Input);
end if;
END Get_Words;
Data : Word_Array(1 .. 1000);
Output : File_Type;
begin
get_words(Data);
Sort (Data);
--Create(F, Ada.Text_IO.Out_File, "output.txt");
Create (File => Output,
Mode => Out_File,
Name => "output.txt");
for I in Data'Range loop
if Data(I).wlen /= 45 then
Put_Line(Output, To_String(Data(I).s & Integer'Image(Data(I).count)));
end if;
end loop;
close(Output);
end v3;
So if the file had:
Hello Hello
Hello World
World World
World
My current output is
Hello 3
World 4
I want my new output to be
Hello 1-2 wc: 3
World 2-3-4 wc: 4

Related

Invaild value of min and max using repeat until loop in pascal

I need use loop from title,but I get incorrect value of result, under my code,please for suggestion, when i use a for everything is ok
const
licz_l = 5;
var
x, suma, min, max: longint;
tab: array [1..5] of longint;
begin
randomize();
suma := 0;
x := 0;
repeat
tab[x] := random(100);
suma := suma + tab[x];
write({'wylosowane liczby : ',}tab[x],';');
min := tab[1];
max := tab[1];
if (tab[x] < min) then
min := tab[x];
// max:=tab[1];
if (max < tab[x]) then
max := tab[x];
x := x + 1;
until x = licz_l;
writeln('');
writeln('srednia : ', suma / licz_l : 4 : 4);
writeln('min : ', min, #9, 'max : ', max);
end.
New code with second loop [for], but like I write, is a posibility to use only one loop[repeat until] to getvthe same effect?
const
licz_l = 5;
var
x, suma, min, max: longint;
tab: array [0..4] of longint;
begin
randomize();
suma := 0;
x := 0;
repeat
tab[x] := random(100);
suma := suma + tab[x];
write({'wylosowane liczby : ',}tab[x],';');
x := x + 1;
until x = licz_l;
min := tab[0];
max := tab[0];
for x := 0 to licz_l-1 do
begin
if (tab[x] < min) then
min := tab[x];
if (max < tab[x]) then
max := tab[x];
end;
writeln('');
writeln('srednia : ',suma/licz_l:4:4);
writeln('min : ',min,#9,'max : ',max);
end.
There are two possible ways to correct your first code (with a single loop).
Remove the lines within the loop: min := tab[1]; and max := tab[1];
Initialize min and max before the loop, with values that are,
on one hand > maximum value that random(100) may return, and
on other hand < minimum value that random(100) may return.
or
Assign min and max unconditionally with the first value, but only the first time your loop runs (if x = 0).
const
licz_l=5;
var
x,suma,min,max: longint;
tab: array [0..4] of longint;
begin
randomize();
suma:=0;
x:=0;
repeat
tab[x]:=random(100);
suma:=suma+tab[x];
write((*'wylosowane liczby : ',*)tab[x],';');
x:=x+1;
until x=licz_l;
min:=tab[0];
max:=tab[0];
for x:=0 to licz_l-1 do
begin
if (tab[x]<min) then
min:=tab[x];
if (max<tab[x]) then
max:=tab[x];
end;
writeln('');
writeln('srednia : ',suma/licz_l:4:4);
writeln('min : ',min,#9,'max : ',max);
end.
Or
const
licz_l = 5;
var
x, suma, min, max: longint;
tab: array [0..4] of longint;
begin
randomize();
suma := 0;
x := 0;
min := 99;
max := 0;
repeat
tab[x] := random(100);
suma := suma + tab[x];
write((*'wylosowane liczby : ',*)tab[x],';');
//min := tab[0];
//max := tab[0];
if (tab[x] < min) then
min := tab[x];
if (max < tab[x]) then
max := tab[x];
x := x + 1;
until x = licz_l;
writeln('');
writeln('srednia : ', suma / licz_l : 4 : 4);
writeln('min : ', min, #9, 'max : ', max);
end.

Sum of squares in an array using recursion in golang

So my friend gave me this task where the sum of squares of positive numbers must be calculated using recursion.
Conditions - The input will be a string with space separated numbers
This is what I've come so far but this shows a runtime error.
Here is the full error https://ideone.com/53oOjN
package main
import(
'fmt',
'strings',
'strconv'
)
var n int = 4
var sum_of_squares int = 0
func sumOfSquares(strArray []string, iterate int) int{
number, _ := strconv.Atoi(strArray[iterate])
if number > 0 {
sum_of_squares += number*number
}
if iterate == n {
return 0 // just to end the recursion
}
return sumOfSquares(strArray, iterate+1)
}
func main() {
str := "1 2 3 4"
strArray := strings.Fields(str)
result := sumOfSquares(strArray, 0)
fmt.Println(sum_of_squares, result)
}
The rule of thumb in recursion is termination condition. It should exist and it should exist in the right place.
func sumOfSquares(strArray []string, iterate int) int{
if iterate >= len(strArray) {
return sum_of_squares
}
number, _ := strconv.Atoi(strArray[iterate]) //TODO: handle err here
sum_of_squares += number*number
return sumOfSquares(strArray, iterate+1)
}
Just for you information: canonical recursion should not save it's state into global fields. I would suggest using following function signature.
func sumOfSquares(strArray []string, iterate, currentSum int) int{
//...
return sumOfSquares(strArray, iterate+1, sum_of_squares)
}
So that you don't need to store sum_of_squares somewhere. You will just pass it to next function invocation.
package main
import (
"fmt"
"strconv"
"strings"
)
var n int
func sumOfSquares(strArray []string, iterate int) int {
number, _ := strconv.Atoi(strArray[iterate])
if iterate == n {
return number * number
}
return ((number * number) + sumOfSquares(strArray, iterate+1))
}
func main() {
str := "1 2 3 4"
strArray := strings.Fields(str)
n = len(strArray) - 1
result := sumOfSquares(strArray, 0)
fmt.Println(result)
}
Indexing starts from 0, so decrease the length by one.
As #peterSO have pointed out, if strings contain unusual characters, it doesn't work, I didn't post the right answer for getting input because you seem to be beginner, but you can read the input, like this instead.
var inp []byte
var loc int
inp, _ = ioutil.ReadFile(fileName)
//add \n so that we don't end up running out of bounds,
//if last byte is integer.
inp = append(inp, '\n')
func scanInt() (res int) {
if loc < len(inp) {
for ; inp[loc] < 48 || inp[loc] > 57; loc++ {
}
for ; inp[loc] > 47 && inp[loc] < 58; loc++ {
res = res<<3 + res<<1 + (int(inp[loc]) - 48)
}
}
return
}
This is faster and scans integers only, and skips all other unusual characters.
I like to keep it simple. I have some few if conditions as well, but hope you like it.
func sumOfSquares(numArr []string) int {
i, err := strconv.Atoi(numArr[0])
rest := numArr[1:]
//Error checking
if err != nil {
fmt.Println(err)
os.Exit(1)
return 0
}
square := i * i
// negative & last number
if i < 0 && len(rest) == 0 {
return square
}
// negative & not last number
if i < 0 && len(rest) > 0 {
return sumOfSquares(rest)
}
// last man standing
if i >= 0 && len(rest) == 0 {
return square
}
return square + sumOfSquares(rest)
}
DEMO : https://play.golang.org/p/WWYxKbvzanJ

Optimizing work with an array of records

I have the following object with an array of a record type:
type
TTimeMark = record
// many fields here
end;
TTimeMarks = array of TTimeMark;
TUserProfile = class(TObject)
TimeLine: TTimeMarks;
....
end;
In this list TUserProfile.TimeLine will be inserted items at run time. I don't know a method of inserting items other than increasing the lenghth of the array with one and then moving all the items a place down until I reach the desired possition. But in this array, the items are records with many fields, so, if I do TimeLine[I]:= TimeLine[I-1], all the data in the memory will be copied from one place to another (am I right ?), and this will take some time. Do you think should I use an array of pointers of that record, instead ? Or is there other fast method to do this ?
This is how I've done.. I used an array of pointers and I make some procedures to easy add, delete and move items:
TPointerArray = array of Pointer;
procedure PArrayInsert(var AArray: TPointerArray; Position: Integer; Count: Integer = 1);
var L, CTail: Integer;
begin
L:= Length(AArray);
if (Count = 0) or (Position > L) then Exit;
SetLength(AArray, L + Count);
CTail:= L - Position;
if CTail > 0 then
Move(AArray[Position], AArray[Position+Count], CTail * SizeOf(Pointer));
end;
procedure PArrayDelete(var AArray: TPointerArray; Position: Integer; Count: Integer = 1);
var L, CTail: Integer;
begin
L:= Length(AArray);
if (L = 0) or (Count = 0) or (Position >= L) or ((Position+Count) > L) then Exit;
CTail:= L - (Position + Count);
if CTail > 0 then
Move(AArray[Position+Count], AArray[Position], CTail * SizeOf(Pointer));
SetLength(AArray, L - Count);
end;
function PArrayMove(var AArray: TPointerArray; FromIndex, ToIndex: Integer; Count: Integer = 1): Boolean;
var L, Size, CT: Integer;
Buff: Pointer;
begin
Result:= False;
L:= High(AArray);
if (FromIndex > L) or (ToIndex > L+1) or
((ToIndex >= FromIndex) and (ToIndex <= (FromIndex+Count))) then Exit;
Size:= Count * SizeOf(Pointer);
GetMem(Buff, Size);
Move(AArray[FromIndex], Buff^, Size);
if FromIndex > ToIndex then begin
CT:= FromIndex - ToIndex;
Move(AArray[ToIndex], AArray[FromIndex+Count-CT], CT * SizeOf(Pointer));
Move(Buff^, AArray[ToIndex], Size);
end
else begin
CT:= ToIndex - FromIndex - Count;
Move(AArray[FromIndex+Count], AArray[FromIndex], CT * SizeOf(Pointer));
Move(Buff^, AArray[FromIndex+CT], Size);
end;
FreeMem(Buff);
Result:= True;
end;

How to sort array of integers with zeros at the end?

I need to sort arrays by integer field, with 1-n sorted at the beginning and zeros last:
0,0,3,1,2 -> 1,2,3,0,0
I don't know how to sort it in one go, so I tried in 2 sorts, but it doesn't produce correct results:
It does put zeros at the end, but it messes up 1-n ordered items:
0,0,3,1,2 -> (first sort) 0,0,1,2,3 -> (second sort) 2,3,1,0,0
procedure TForm2.Button1Click(Sender: TObject);
var
Arr: TArray<integer>;
begin
SetLength(Arr, 5);
Arr[0] := 0;
Arr[1] := 0;
Arr[2] := 3;
Arr[3] := 1;
Arr[4] := 2;
// First sort: Sort 1-n
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if Left < Right then
Result := -1
else if Left > Right then
Result := 1
else
Result := 0;
end
));
// Second sort: Put zeros at the end
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if (Left = 0) and (right>0) then
Result := 1
else
Result := 0;
end
));
end;
Is there a way to do this kind of sort in one, single Sort operation?
Try this, the point being to deal with the special 0 cases first in the if-then-else ladder, before the ordinary cases.
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if (Left = 0) and (Right = 0) then
Result := 0
else if (Left = 0) then
Result := 1
else if (Right = 0) then
Result := -1
else if (Left < Right) then
Result := -1
else if (Left > Right) then
Result := 1
else
Result := 0;
end
));
A brief testing shows it works OK.
Just fix your compare function so that it will treat 0 as being larger than anything.
Untested:
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if Left = Right then
Result := 0
else if ((Left <> 0) and (Left < Right)) or (Right = 0) then
Result := -1
else
Result := 1;
end
));

Does Free Pascal have a way to concatenate arrays?

Pascal apparently has string concatenation, but does it have general concatenation for any type of array?
It does not but you can make your own function i coded this in 5 minutes...i am shure there is a better method but i don't have any idea right now.
type
TBArray = array of byte;
function ConcArray(arr1,arr2:TBArray):TBArray;
begin
SetLength(Result,Length(arr1) + Length(arr2));
ZeroMemory(#Result[0],Length(arr1) + Length(arr2));
CopyMemory(#Result[0],#arr1[0],Length(arr1));
CopyMemory(#Result[Length(arr1)],#arr2[0],Length(arr2));
end;
How about this? If you need to concatenate in many places, the + operator looks pretty nice IMHO.
program ConCatTest;
type
SomeRec = record
s: AnsiString;
i: Longint;
end;
SomeArr = array of SomeRec;
operator + (a, b: SomeArr) c: SomeArr;
var
i: Longint;
begin
SetLength(c, Length(a) + Length(b));
for i := 0 to High(a) do
c[i] := a[i];
for i := 0 to High(b) do
c[i + Length(a)] := b[i];
end;
var
a1, a2, a3: SomeArr;
i: Longint;
begin
SetLength(a1, 3);
SetLength(a2, 2);
a1[0].s := 'a';
a1[0].i := 0;
a1[1].s := 'a';
a1[1].i := 1;
a1[2].s := 'a';
a1[2].i := 2;
a2[0].s := 'b';
a2[0].i := 0;
a2[1].s := 'b';
a2[1].i := 1;
a3 := a1 + a2;
for i := 0 to High(a3) do
WriteLn(a3[i].s, a3[i].i);
ReadLn;
end.

Resources