### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: Stem and Leaf Plot  (Read 5840 times)

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Operator not Overloaded Error How to fix?
« Reply #15 on: September 29, 2023, 07:00:31 am »
Yes now it's splitting with #32.
But I don't get the numbers being grouped like

1  |   2 4 6
2  |   1 2 3

I get

1  2
1  4
1  6
2  1
2  2
2  3

It's like        plot.leaf := plot.leaf + '  ' + IntToStr(leaf)      so that next leaf value is added to previous leaf value.

Perhaps the operator in  needed to include extra condition ?
« Last Edit: September 29, 2023, 07:06:32 am by Boleeman »

#### TRon

• Hero Member
• Posts: 1864
##### Re: Operator not Overloaded Error How to fix?
« Reply #16 on: September 29, 2023, 07:05:54 am »
But I don't get the numbers being grouped like
Strange. where did you put in 6 then ?

as an example at my side:
Quote
Enter input: 12 32 34 54 34
found 5 lines
line[0] = "12"
1  2
line[1] = "32"
3  2
line[2] = "34"
3  4
line[3] = "54"
5  4
line[4] = "34"
3  4
press enter to continue
Which, afaik, is exactly what your code is suppose to do ?

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Operator not Overloaded Error How to fix?
« Reply #17 on: September 29, 2023, 07:10:41 am »
12 13 14 21 22 31

would like it to appear as

1   2  3  4
2   1  2
3   1

so that the tens appear in the stem (red)

Does if plot.stem in plot then    check if each leaf value is part of particular stem  (row, like 10's row, 20's row)?
« Last Edit: September 29, 2023, 07:22:02 am by Boleeman »

#### TRon

• Hero Member
• Posts: 1864
##### Re: Operator not Overloaded Error How to fix?
« Reply #18 on: September 29, 2023, 07:20:05 am »
Does if plot.stem in plot then    check if each leaf value is in the particular part of each stem?
Ah understood. thank for the number example.

No, somehow you expect the in operator to also magically return the index to the stem so that you can use that index to add your leaf to the correct stem. All the operator does is check if a stem exist. If it does it then returns true. And that is all you are going to get from a for..in operator overload unless working with global variables in the operator (which is a terrible idea to be doing).

You would need to craft a special subroutine that returns a boolean when the stem exist, a var parameter that returns the stem index (so that you can use that to add your leaf to the correct stem), a parameter to your plot array and a string parameter for the stem you are searching for.
« Last Edit: September 29, 2023, 07:27:22 am by TRon »

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Operator not Overloaded Error How to fix?
« Reply #19 on: September 29, 2023, 07:25:54 am »
OK maybe we will leave it for now. More work to be done (craft a special subroutine that returns a boolean when the stem exist, a var parameter that returns the stem index (so that you can use that to add your leaf to the correct stem), a parameter to your plot array and a string parameter for the stem you are searching for)

Kinda glad I learnt a bit about the Operator not Overloaded Error and thanks to you for the operator in

I thought that it would be easy to make a stem and leaf plot, but it looks a bit harder than I anticipated.

Much appreciated. I got a bit lost so have to appologize.

« Last Edit: September 29, 2023, 07:35:45 am by Boleeman »

#### TRon

• Hero Member
• Posts: 1864
##### Re: Operator not Overloaded Error How to fix?
« Reply #20 on: September 29, 2023, 07:29:57 am »
So this is being executed all the time

plot.leaf := IntToStr(leaf);

writeln(plot.stem, plot.leaf);

and not  plot.leaf := plot.leaf + '  ' + IntToStr(leaf)
Not for me. and I already explained why it doe snot work as you expected.

Code: [Select]
`    if plot[i].stem in plot then    begin      writeln('found stem: ', plot[i].stem);      plot[i].leaf := plot[i].leaf + '  ' + IntToStr(leaf)    end`
and that outputs:
Code: [Select]
`Enter input: 12 32 34 54 34found 5 linesline[0] = "12"found stem: 1stem:1  leaf:  2line[1] = "32"found stem: 3stem:3  leaf:  2line[2] = "34"found stem: 3stem:3  leaf:  4line[3] = "54"found stem: 5stem:5  leaf:  4line[4] = "34"found stem: 3stem:3  leaf:  4press enter to continue`\
Each "found stem" printout indicates that the line that you talk about is actually executed. You are using the wrong logic for adding the leaf to the correct stem.

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Operator not Overloaded Error How to fix?
« Reply #21 on: September 29, 2023, 07:37:57 am »
I thought that it would be easy to make a stem and leaf plot, but it looks a bit harder than I anticipated.

Much appreciated. I got a bit lost so have to appologize.

OK maybe we will leave it for now. More work to be done (craft a special subroutine that returns a boolean when the stem exist, a var parameter that returns the stem index (so that you can use that to add your leaf to the correct stem), a parameter to your plot array and a string parameter for the stem you are searching for)

Kinda glad I learnt a bit about the Operator not Overloaded Error and thanks to you for the operator in

#### TRon

• Hero Member
• Posts: 1864
##### Re: Operator not Overloaded Error How to fix?
« Reply #22 on: September 29, 2023, 08:17:22 am »
@Boleeman:
Since this seem to be your second or third attempt at this, I have modified your original code (loads of commented out code and additional comments). I would rather see that you struggled with it a bit longer yourself so that the lesson learned can never be forgotten but I do not like having you get stuck at this either. You decide for yourself what you want to do as you can always ignore this post if wanted.

Code: Pascal  [Select][+][-]
1. program stem_and_leaf;
2.
3. {\$mode objfpc}{\$H+}
4.
5. uses
6.   crt, sysutils;
7.
8. type
9.   TPlotItem = record
10.     stem: string;
11.     leaf: string;
12.   end;
13.
14.   TPlotItems = array of TPlotItem;
15.
16. var
17.   Plot: TPlotItem;
18.   Plots: TPlotItems = nil;
19.
20.   inputstring: string;
21.   lines: array of string;
22.   num, leaf, stem: integer;
23.   i: integer;
24.
25.   StemIndex: integer;
26.   StemString: string;
27.
28.
29. function FindStemIndexInPlotArray(aStem: string; aPlots: TPlotItems; var aStemIndex: integer): boolean;
30. var
31.   Plot : TPlotItem;
32. begin
33.   result := false;
34.   aStemIndex := 0;
35.   for Plot in aPlots do
36.   begin
37.     if aStem = Plot.Stem
38.       then exit(true);
39.     inc(aStemIndex);
40.   end;
41. end;
42.
43. begin
44.   clrscr;
45.
46.   write('Enter input: ');
48.
49.   lines := inputstring.Split(#32);
50.   writeln('found ', length(lines), ' lines');
51.
52.   for i := 0 to Length(lines) - 1 do
53.   begin
54.     writeln('line[', i, '] = "', lines[i], '"');
55.     num := StrToInt(lines[i]);
56.     leaf := Abs(num mod 10);
57.     stem := num div 10;
58.
59.     if (num < 0) and (num > -10)
60.       then stem := -0;
61.
62.     // there is no relation between Lines index variable i and
63.     // the actual stemindex. You can literally have 1000 lines with the number
64.     // 11 but that means that there is only one single stem
65.     // we do need to keep track of the stem though as we need to search for it
66.     // later so store it into a string for now.
67.     //    plot[i].stem := IntToStr(stem);
68.     stemstring := IntToStr(stem);
69.
70.     if FindStemIndexInPlotArray(StemString, Plots, StemIndex) then
71.     begin
72.       // Again there is no relation between the lines index i and the actual stem index.
73.       //      writeln('found stem: ', plot[i].stem, ' at index ', stemindex, ' current index = ', i);
74.       writeln('found stem: ', StemString, ' at stem index ', StemIndex, ' current line index = ', i);
75.       Plots[StemIndex].leaf := Plots[StemIndex].leaf + '  ' + IntToStr(leaf)
76.     end
77.     else
78.     begin
79.       // if the stem does not exist yet then we need to add another plot to the plots array
80.       // first we make room for another entry in the array
81.       SetLength(Plots, length(Plots) + 1);
82.       // again no relation between lines index i and stem index
83.       //      plot[i].leaf := IntToStr(leaf);
84.       // add the new stem with its leaf
85.       Plots[High(Plots)].stem := StemString;
86.       Plots[High(Plots)].leaf := IntToStr(leaf);;
87.     end;
88.
89.     // we can not print the plots array here because there is no relation between
90.     // the line index i and the actual stems.
91.     // so any writeln using the i index will result in falsified information.
92. (*
93.     if plot[i].stem in plot then
94.     begin
95.       writeln('found stem: ', plot[i].stem);
96.       plot[i].leaf := plot[i].leaf + '  ' + IntToStr(leaf)
97.     end
98.     else
99.       plot[i].leaf := IntToStr(leaf);
100. *)
101.
102. //    writeln('stem:', plot[i].stem, '  leaf:', plot[i].leaf);
103.   end;
104.
105.   // after all the lines are processed the plots array can be printed
106.   writeln;
107.   writeln('list of stems and leaves');
108.   writeln;
109.   for plot in plots
110.     do writeln('stem:', plot.stem, '  leaf:', plot.leaf);
111.
112.
113.   writeln('press enter to continue');
115. end.
116.

If you do use it, make sure to clean up the comments and add your own so that it becomes clear /for you/.

PS: initially I did not understood that you wanted to do this
« Last Edit: September 29, 2023, 08:22:23 am by TRon »

#### cdbc

• Hero Member
• Posts: 722
##### Re: Operator not Overloaded Error How to fix?
« Reply #23 on: September 29, 2023, 08:42:11 am »
Hi
Well, @TRon beat me to it, so here's my take on it:
Code: Pascal  [Select][+][-]
1. program test;
2.
3. {\$mode objfpc}{\$H+}
4.
5. uses crt, sysutils;
6.
7.
8. type
9.   TPlot = record
10.     stem: string;
11.     leaf: string;
12.   end;
13.
14.   TPlotArray = array of TPlot;
15.
16. var
17.   plot: TPlotArray;
18.   minput,strem: string; // bc... "strem" is a string version of stem, for search purposes
19.   lines: array of string;
20.   num, leaf, stem: integer;
21.   i,idx: integer; // bc... "idx" is used as return/out value in search
22. (*
23. operator in (const A: string; const B: TPlotArray): boolean;
24. var
25.   C: TPlot;
26. begin
27.   result := false;
28.   for C in B do
29.   begin
30.     if C.stem = A then exit(true);
31.   end;
32. end;
33. *)
34.
35. { StemInPlot checks if a stem is present in a plotarray, if so, it returns true and the idx of occurrence
36.   in "anIndex"; if not so, it returns false and -1 in "anIndex" }
37. function StemInPlot(const aStem: string; const aPlotArray: TPlotArray;out anIndex: integer): boolean;
38. var
39.   i: integer;
40. begin
41.   result := false; anIndex:= -1;
42.   for i:= low(aPlotArray) to high(aPlotArray) do begin
43.     if aPlotArray[i].stem = aStem then begin
44.       anIndex:= i;
45.       exit(true);
46.     end;
47.   end;
48. end;
49.
50. begin
51.   clrscr;
52.
53.   write('Enter input: ');
55.
56.   lines := minput.Split([#32]);
57.   SetLength(plot, Length(lines));
58.
59.   for i := 0 to Length(lines) - 1 do
60.   begin
61.     num := StrToInt(lines[i]);
62.     leaf := Abs(num mod 10);
63.     stem := num div 10;
64.
65.     if (num < 0) and (num > -10) then
66.       stem := -0;
67.
68.     // bc...
69.     strem:= IntToStr(stem); // string version of stem, for search purposes
70.     if StemInPlot(strem,plot,idx) then begin
71.       plot[idx].leaf := plot[idx].leaf + '  ' + IntToStr(leaf);
72.       writeln('stem: ',plot[idx].stem,', leaf: ',plot[idx].leaf);
73.     end else begin
74.       plot[i].stem := strem;
75.       plot[i].leaf := IntToStr(leaf);
76.       writeln('stem: ',plot[i].stem,', leaf: ',plot[i].leaf);
77.     end;
78.     // end bc...
80.     plot[i].stem := IntToStr(stem);
81.
82.     if plot[i].stem in plot then
83.       plot[i].leaf := plot[i].leaf + '  ' + IntToStr(leaf)
84.     else
85.       plot[i].leaf := IntToStr(leaf);
86.
87.     writeln('stem: ',plot[i].stem,', leaf: ',plot[i].leaf);
88. *)
89.   end; // loop
90.
91.   writeln('tap enter to stop');
93. end.
94.
Regards Benny
If it ain't broke, don't fix it
PCLinuxOS(rolling release) -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Operator not Overloaded Error How to fix?
« Reply #24 on: September 29, 2023, 10:47:07 am »
Sorry about the fast exit TRon.
Been feeling a bit sick. I had a massive migraine and nausea ...followed by some vomiting.

Many thanks to TRon and cdbc (Benny).

I will look over both codes especially function FindStemIndexInPlotArray and function StemInPlot

#### TRon

• Hero Member
• Posts: 1864
##### Re: Operator not Overloaded Error How to fix?
« Reply #25 on: September 29, 2023, 11:30:00 am »
@Boleeman:
No need to worry, hurry or explain yourself. Just take your time to let it sink in.

If there is anything you should try and learn from this it is that using some simple writeln's are able to explain everything in detail and you can go as detailed as you wish to have it.

Ofc using a debugger and inspecting the values you are interested in can do the same thing (in which case you have to remember a bit more because the values changes over each iteration).

cdbc's StemInPlot() function is imho more clear and definitely written in a more neatly manner but basically our functions do exactly the same: given the stem string, search for that stemstring in the array. If the stemstring already exist the function then return a true value as result /and/ return the (array) index to that stem (and therefor also the leaf) is returned.

If the stemstring was not found (function returns value false) then the returned array index is invalid and can not be used.

I am personally more concerned about the characteristics of such a stemplot table because there does not seem to be any consensus regarding sorting (yes or no sort the values beforehand), support for empty stems (according to some documentation it is mandatory while other documentation stated it should be optional) and how to handle negative numbers and/or real numbers seem also to depend on what documentation you read.

I am definitely not a statistical analyst so would have no idea, not even what would be the proper source for documentation.

@cdbc:
Sorry for that. Love your StemInPlot solution btw !

#### cdbc

• Hero Member
• Posts: 722
##### Re: Operator not Overloaded Error How to fix?
« Reply #26 on: September 29, 2023, 01:15:28 pm »
Hi
@TRon: No worries mate  Glad you like it, kinda wrote itself
Tihi, in return, I love your operators
If one should dive into it, one would probably write a typehelper for "TPlotArray", covering both the search function and some sorting functions etc.
@Boleeman: Hope you get well soon and back on track
Regards Benny
If it ain't broke, don't fix it
PCLinuxOS(rolling release) -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Operator not Overloaded Error How to fix?
« Reply #27 on: October 06, 2023, 10:51:31 pm »
Sorry about the quick exit, as I ended up being quite sick from being very dehydrated (it was hot that day and I was not drinking enough fluids).

With the Stem and Leaf plot I was wondering how to include the in between 10's values in the stem

When there are no values there like for 10, 45, 55, 42 I get

1  |  0
4  |  5    2
5  |  5

What I wanted was the inclusion of 20's and 30's in the stem and the numbers in ascending order.

1  |  0
2  |
3  |

4  |  2    5
5  |  5

I think it has something to do with putting the numbers in an array, sorting them and finding the:

stemMax := MaxIntValue(arr) div 10;
stemMin := MinIntValue(arr) div 10;

so as to fill in the missing 10's values in the stem and having all the numbers sorted before being put into the plot.

I thought of originally putting all the integers in a stringlist on a form and sorting them, then finding stemMin and stemMax to create the stem

Lastly place the Stem numbers in a TMemo and put the values in the leaf.

« Last Edit: October 06, 2023, 11:24:34 pm by Boleeman »

#### TRon

• Hero Member
• Posts: 1864
##### Re: Operator not Overloaded Error How to fix?
« Reply #28 on: October 07, 2023, 12:43:16 am »
...
With the Stem and Leaf plot I was wondering how to include the in between 10's values in the stem
...

As I wrote in one of my previous replies: I am more concerned about the characteristics of the stemplot table as there seem to be no consensus.

So if you want to change the characteristics (of the stemplot table) you need to find another approach.

One of them could indeed be as you wrote/suggested.

I would personally try another approach. Having said that, it is just /an/ approach and there are probably many approaches possible that lead to the same result. So take the following with keeping that in mind. I tried to stay as close to something that can be explained and/or implemented  in an easy way.

Currently you have split up the textual representation of numbers into lines so that every number has its own line.

I would convert these numbers into integers and store them into a dynamic array of integers.

When these numbers are stored into a dynamic array they can easily be sorted from lowest to highest number (see wiki about sorting for example). That will take care of a few things:
- the lowest number is located at the first entry of the array
- the highest number is located at the last entry of the array
- the numbers are in perfect order for a stemplot table because they are stored and can be processed from low to high

You can then take the lowest number and extract the stem from it, and you can do the same for the highest number (therefor highest stem).

Now that you know the lowest and highest stem you know which (other) stems need to be present in between those two extremes. Ergo you can iterate between those two extremes in order to fill in the missing stems.

You add all those stems (including lowest and highest) to the stemplot table but omit the leaves for now.

Then you can iterate over the dynamic number array again, extract the stem (and leaf), try to locate the stem in the stemplot table and add the leaf just as you did before.

The main difference is that in the way I present things I would prefer a stemplot table that uses integer numbers instead of strings but in theory you can choose either way (conversion between integers and strings are simple to implement).

There is probably a much better, faster and more logical approach possible but the main advantage (I think) for this presented approach is that you are able to split up different parts of the process that I mentioned in different subroutines that can all do one (small) specific part of the process as described.

What do you think yourself ?

PS: This time I did not prepare anything so if anyone else would want to take a stab at it...

#### Boleeman

• Sr. Member
• Posts: 253
##### Re: Stem not including missing tens. How to add missing 10's?
« Reply #29 on: October 13, 2023, 11:06:40 am »
Ended up playing with a constant array of test values and got the required missing tens results plus sorted order of numbers.

for stem := min div 10 to max div 10 do  did the trick of the missing tens in the stem

Now I need to convert to dynamic array and Windows Forms to either input the data from a comma delimited text file of integer values or from a memo containing integer data values.

Code: Pascal  [Select][+][-]
1. program project1;
2.
3. {\$MODE OBJFPC}{\$H+}
4.
5. uses
6.   SysUtils;
7.
8. const DataArray: array[1..20] of Integer = (19,27,28,42,39,53,42,18,44,70,44,37,23,44,37,48,24,36,29,31);
9.
10. var
11.   i, j, min, max, p, stem, temp: Integer;
12. begin
13.   for i := 1 to 20 do
14.   begin
15.     for j := 1 to 20 - i do
16.     begin
17.       if DataArray[j] > DataArray[j + 1] then
18.       begin
19.         temp := DataArray[j];
20.         DataArray[j] := DataArray[j + 1];
21.         DataArray[j + 1] := temp;
22.       end;
23.     end;
24.   end;
25.   min := DataArray[1];
26.   max := DataArray[20];
27.   p := 1;
28.   for stem := min div 10 to max div 10 do
29.   begin
30.     Write(stem, ' | ');
31.     while (p <= 20) and (DataArray[p] div 10 = stem) do
32.     begin
33.       Write(DataArray[p] mod 10, ' ');
34.       p := p + 1;
35.     end;
36.     Writeln;
37.   end;
38.   sleep(1000);
39. end.
40.

« Last Edit: October 13, 2023, 11:12:16 am by Boleeman »