Lazarus

Free Pascal => Beginners => Topic started by: Ten_Mile_Hike on January 17, 2025, 11:10:10 pm

Title: [Solved] A Tip for beginners
Post by: Ten_Mile_Hike on January 17, 2025, 11:10:10 pm
Just a reminder that when iterating over a string and inserting or deleting characters you have
to use "Downto" not "To" to get your expected results when processing multiple characters.

In this case below the expected result is the removal of all '4' characters from the string.
ie. 'AB4C44DE' becomes ABCDE'.

I leave it as an exercise for the newbie to understand why this is so.

P.S. Yes; I know that there are a myriad of ways to attack this problem. This example is for newbies

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   S: string;
  4.   x: integer;
  5. begin
  6.  
  7.   S := '412345446444474';
  8.   for x := 1 to length(S) do if s[x] = '4' then Delete(S, x, 1);
  9.   Memo1.Lines.add(S); //Result '123546447' is incorrect
  10.  
  11.   S := '412345446444474';
  12.   for x := Length(S) downto 1 do if s[x] = '4' then Delete(S, x, 1);
  13.   Memo1.Lines.add(S); //Result '123567' is correct
  14. end;                
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 10:10:04 am
It's better to remind beginners to turn on checks (at least -Ciro) and use debugger while developing, because the line
Code: Pascal  [Select][+][-]
  1. for x := 1 to length(S) do if s[x] = '4' then Delete(S, x, 1);

raises Range check error.
Title: Re: A Tip for beginners
Post by: Thaddy on January 18, 2025, 10:55:56 am
@tetrastes
You are not a beginner. Downto is better. Do you really want me to give you the answer?  ;)
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 11:25:04 am
Of course downto is better, as to is simply buggy. ;) And the answer is obvious after seeing range check error, particularly for a beginner.
Are you against using checks and debugger?
Title: Re: A Tip for beginners
Post by: Thaddy on January 18, 2025, 11:36:30 am
No, I am against re-allocations... ;D
Title: Re: A Tip for beginners
Post by: cdbc on January 18, 2025, 12:02:04 pm
Hi
@tetrastes:
Quote
downto is better, as to is simply buggy.
NO 'to' is not buggy!!!
The reason you can't use 'to' in that situation, is because you're deleting char(s) as you go, thereby changing the count of items, which in turn screws up your loop!!!
Regards Benny
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 12:26:49 pm
@cdbc
If we can say "downto is better", why we can't say "to is buggy"?  :D
I think it was obvious, what these meant. Why deprive newbies of finding the answer themselves?
Title: Re: A Tip for beginners
Post by: dbannon on January 18, 2025, 12:38:05 pm
If we can say "downto is better", why we can't say "to is buggy"?  :D


(I am not suggesting we should not call out real bugs for that reason !)

Davo
Title: Re: A Tip for beginners
Post by: cdbc on January 18, 2025, 12:42:06 pm
Thanks Davo, exactly my thoughts  ;)
Regards Benny
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 12:51:23 pm
It's strange to me that someone understand this phrase verbatim. I think its meaning was clear in the context of discussion.
Of course I don't think that "to is buggy" by itself. And that "downto is better" always and everywhere.  :D
Title: Re: A Tip for beginners
Post by: Thaddy on January 18, 2025, 02:17:28 pm
@ tetrastes

You still don't get it, do you?
Removing chars with downto does not re-allocate memory for the whole string.
It just performs a move on the string tail. There is no need for reallocmem. It shrinks.
Removing chars with to, from zero,  DOES re-allocate memory for the whole string every time and is therefor considerably slower, calls reallocmem/getmem, move and freemem on every occasion.
So much for the beginners!
There, I gave it away. >:D
Basics, basics, basics. O:-)

It was a genuinely good question for beginners and then an old hand falls in the same trap and forces me to reveal the answer.

Shame on you  ::)

(at least the beginners now have the explanation)

Otherwise it is my opinion that to is not buggy. (who invented that novelty?)
Actually that is fact, not opinion, but I was watching a documentary about Carthage, "Ceterum censeo Carthaginem esse delendam,"  %).
Title: Re: A Tip for beginners
Post by: MarkMLl on January 18, 2025, 03:10:02 pm
It's strange to me that someone understand this phrase verbatim. I think its meaning was clear in the context of discussion.
Of course I don't think that "to is buggy" by itself. And that "downto is better" always and everywhere.  :D

In that case choose your words better: "to is /inappropriate/ in this case" is the correct way of putting it, particularly in something which is labelled as being for beginners.

However I'd also point out that since we're discussing strings here, with no indication of the encoding, it's necessary to take into account that if UTF-8 characters are involved the result might still be unexpected.

MarkMLl
Title: Re: A Tip for beginners
Post by: Thaddy on January 18, 2025, 03:15:26 pm
Oh, Mark,
He has no clue anyway, why bother to overload his brain? :'(
Title: Re: A Tip for beginners
Post by: LV on January 18, 2025, 04:47:53 pm
This is excellent advice. But this

Code: Pascal  [Select][+][-]
  1.   S := '412345446444474';
  2.   for x := 1 to length(S) do if s[x] = '4' then Delete(S, x, 1);
  3.   Memo1.Lines.add(S); //Result '123546447' is incorrect
  4.  

is usually called a beginner programmer's mistake, not an FPC bug. Isn't it?
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 04:50:31 pm
@Thaddy

Though you like to insult people, I'll still answer you.

1. I didn't give any answer on OP's question, so why "shame on me"?  :D

2. Your answer explaines nothing, though it contains much bragging, as usual. The code with "to" doesn't work not because of reallocations and other stuff (which is problem of inefficiency only). If there was implementation without reallocation, it still wouldn't work, because it is mathematically incorrect. And I won't write more, let beginners think themselves (though @cdbc gave the clue).

But to illustrate this:
Code: Pascal  [Select][+][-]
  1.   S := '412345446444474';
  2.   x := 1;
  3.   repeat
  4.       if s[x] = '4' then Delete(S, x, 1)
  5.       else Inc(x);
  6.   until x = length(S)+1;
This code works despite all reallocations, etc.
Title: Re: A Tip for beginners
Post by: jamie on January 18, 2025, 04:58:33 pm
I think it's faster to simply create an empty string with length set to the current length and then copy char to this string that is valid. At the end reset the length.
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 05:04:36 pm
Even simpler, without set/reset length:
Code: Pascal  [Select][+][-]
  1.   S := '412345446444474';
  2.   S1 := '';
  3.   for x := 1 to length(S) do if s[x] <> '4' then S1 := S1 + S[x];

But the aim of OP was not to find the best algorithm...
Title: Re: A Tip for beginners
Post by: TRon on January 18, 2025, 05:05:52 pm
@jamie:
While that is true (phun intended) I believe the idea from TS was for the beginner reading it to figure out.

We are all able to come up with better/other approaches as indicated by TS but it is besides the point. Using a loop this way is a classic beginner error and when not aware might throw that beginner off-guard. It seem to happen on a regular basis when someone post a similar question about deleting items from a list.
Title: Re: A Tip for beginners
Post by: MarkMLl on January 18, 2025, 05:09:54 pm
I think it's faster to simply create an empty string with length set to the current length and then copy char to this string that is valid. At the end reset the length.

No doubt. However OP was trying to contribute a "guide for the perplexed" for the beginner who found himself afflicted by unexpected behaviour: not (I emphasise) a bug in the language definition or implementation, but usually resulting in a bug in the program being written.

MarkMLl
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 05:22:43 pm
It's strange to me that someone understand this phrase verbatim. I think its meaning was clear in the context of discussion.
Of course I don't think that "to is buggy" by itself. And that "downto is better" always and everywhere.  :D

In that case choose your words better: "to is /inappropriate/ in this case" is the correct way of putting it, particularly in something which is labelled as being for beginners.

MarkMLl

I will improve, my general, sir!  O:-)  :D
Title: Re: A Tip for beginners
Post by: Thaddy on January 18, 2025, 05:37:20 pm
@tetrastes

You are a nitwit, a great pretender,
Interpreting smilies is an art. (not)
If you want to be right, then please be right. I think I was not offensive at all. And I was right and still am. That is a fact, not opinion. All you get is - later - noise and that noise does not deviate from the fact you have no clue.
The answer is simply about efficient memory handling. Nothing more. Whatever the string indexiing method: we have zero based strings too, btw.
Can the cause of the noise please shut up? - that is not you -

The correct answer is as I have given.

The noise can delve into {$ZEROBASEDSTRINGS ON}

 :P

Now show me wtf is a better answer than mine: you guessed, you can't. >:D >:D >:( >:( :o
Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 05:48:12 pm
The answer is simply about efficient memory handling. Nothing more.

I showed you example of very inefficient, but properly working code, did I?
Title: Re: A Tip for beginners
Post by: Thaddy on January 18, 2025, 05:52:12 pm
Code works, but is slow for the reasons I explained: excessive memory copying and (re-de-) allocation. That is the beginner stuff.

It is not about if code works, it is about why the code is extremely inefficient.
The question is really about optimization and efficient algorithms. 8)
Title: Re: A Tip for beginners
Post by: 440bx on January 18, 2025, 05:57:41 pm
@tetrastes

You are a nitwit, a great pretender,
Look who's talking... LOL


Title: Re: A Tip for beginners
Post by: tetrastes on January 18, 2025, 06:11:05 pm
It is not about if code works, it is about why the code is extremely inefficient.
The question is really about optimization and efficient algorithms. 8)

Clean your glasses and reread the first post.  8-)
Title: Re: A Tip for beginners
Post by: dbannon on January 18, 2025, 11:30:59 pm
Seriously folks, I am getting quite worried about the trend here. If someone posts bad code, get stuck into it. If someone says something silly, call it out.

But there is absolutely no reason to be firing off personal insults, especially unsupportable ones. Apart from causing offense to people who are, basically like minded, it does leave questions about your own technical knowledge, if you cannot explain the technical problem, is it easier to attack the person ?

Please, a bit of respect for your fellow forum users please !

Davo

Title: Re: A Tip for beginners
Post by: silvercoder70 on January 19, 2025, 01:15:01 pm
It can work moving forwards ... :)

Code: Pascal  [Select][+][-]
  1. procedure RemoveCharInPlace(var str: string; charToRemove: Char);
  2. var
  3.   i, j: Integer;
  4. begin
  5.   j := 1;
  6.   for i := 1 to Length(str) do
  7.   begin
  8.     if str[i] <> charToRemove then
  9.     begin
  10.       if i <> j then // Only assign if i and j are different
  11.         str[j] := str[i];
  12.       Inc(j);
  13.     end;
  14.   end;
  15.   SetLength(str, j - 1);
  16. end;
Title: Re: A Tip for beginners
Post by: dseligo on January 19, 2025, 03:05:08 pm
It can work moving forwards ... :)

Nice. Although, this one would be hard to adapt to work with UTF.
Title: Re: A Tip for beginners
Post by: Thaddy on January 19, 2025, 03:07:02 pm
It is plain wrong, utf8 or not. the setlength causes a relocation.
Title: Re: A Tip for beginners
Post by: Joanna from IRC on January 20, 2025, 01:20:31 pm
I’m surprised to see people arguing over something so basic.
Downto , {descending index} is the correct way to approach anything that might be reduced in length. Only a genuine newbie would not know this.

It has nothing to do with memory allocation , it has to do with the items referenced by indices changing when an item is deleted. In fact if anything is removed your program will probably crash when you reach the last index and try to reference something that is no longer there.
Title: Re: A Tip for beginners
Post by: Thaddy on January 20, 2025, 01:21:22 pm
Almost Correct: it has to do with memory allocation, because traversing downwards keep the location itself in place ( same pointer) traversing upwards does not do that, so you will loose speed by reallocmem. You can test that by tracking the pointer(s).
Title: Re: A Tip for beginners
Post by: Joanna from IRC on January 20, 2025, 01:28:42 pm
Well obviously less memory is allocated as things are deleted. But for explaining to a newbie I’d try to explain it in a less technical terminology.  :)
Title: Re: A Tip for beginners
Post by: MarkMLl on January 20, 2025, 02:22:14 pm
Well obviously less memory is allocated as things are deleted. But for explaining to a newbie I’d try to explain it in a less technical terminology.  :)

The thread's been thoroughly Thaddy'd.

Don't laugh, since I'm quite likely to refer to other threads as being Joanna'd: the difference is that you introduce wibble rather than otiose complexity.

MarkMLl
Title: Re: A Tip for beginners
Post by: BrunoK on January 20, 2025, 02:32:33 pm
It can work moving forwards ... :)

Nice. Although, this one would be hard to adapt to work with UTF.
Wouldn't change anything difficulty wise. Delete deletes 1 byte, so same problem.

If related to silvercoder70 :
It is plain wrong, utf8 or not. the setlength causes a relocation.
No it doesn't, the final setlength just changes the internal string length without reallocating memory.

I’m surprised to see people arguing over something so basic.
Downto , {descending index} is the correct way to approach anything that might be reduced in length. Only a genuine newbie would not know this.

It has nothing to do with memory allocation , it has to do with the items referenced by indices changing when an item is deleted. In fact if anything is removed your program will probably crash when you reach the last index and try to reference something that is no longer there.
Nonsense generalization. In this case, delete internally calls SetLength for each deleted character.

Almost Correct: it has to do with memory allocation, because traversing downwards keep the location itself in place ( same pointer) traversing upwards does not do that, so you will loose speed by reallocmem. You can test that by tracking the pointer(s).
Nonsense, silvercoder70's code doesn't touch the location. You didn't trace the code, the pointer to the AnsiRec doesn't change.

Well obviously less memory is allocated as things are deleted. But for explaining to a newbie I’d try to explain it in a less technical terminology.  :)
Just repeating the nonsense of Thaddy in the case of the original code doesn't make you look very helpful.



Title: Re: A Tip for beginners
Post by: Joanna from IRC on January 20, 2025, 03:02:23 pm
I don’t understand how a simple question about which algorithm is better turned into all this drama.  :D
Title: Re: A Tip for beginners
Post by: dseligo on January 20, 2025, 03:05:16 pm
It can work moving forwards ... :)

Nice. Although, this one would be hard to adapt to work with UTF.
Wouldn't change anything difficulty wise. Delete deletes 1 byte, so same problem.

Silvercoder70's solution doesn't use delete.
Title: Re: A Tip for beginners
Post by: BrunoK on January 20, 2025, 03:05:37 pm

Don't laugh, since I'm quite likely to refer to other threads as being Joanna'd: the difference is that you introduce wibble rather than otiose complexity.

MarkMLl
Joanna'd, good and accurate :-)
Title: Re: A Tip for beginners
Post by: BrunoK on January 20, 2025, 03:13:22 pm
Silvercoder70's solution doesn't use delete.
I know it doesn't use delete. It use pull down with a single final length actualization. Nearly the same code I would write.
Title: Re: A Tip for beginners
Post by: MarkMLl on January 20, 2025, 03:17:11 pm
I don’t understand how a simple question about which algorithm is better turned into all this drama.  :D

It's not.

OP made a good point, based on elementary Pascal, relating to a problem that I'm damn well sure has caught absolutely everybody at some point.

All this introduction of memory allocation etc., i.e. much deeper than is considered in elementary Pascal, has definitely made it worser.

MarkMLl
Title: Re: A Tip for beginners
Post by: BrunoK on January 20, 2025, 03:27:09 pm
OP made a good point, based on elementary Pascal, relating to a problem that I'm damn well sure has caught absolutely everybody at some point.
So true !

For example, the question is relevant when removing objects from Lists and many other situations.

Do we remove from the tail or from the head, and if done from the head how to pack without doing to many memory moves etc... Shall one mark a released item with nil and other points that any average programmer should be able to handle.

Title: Re: A Tip for beginners
Post by: Ten_Mile_Hike on January 20, 2025, 03:55:00 pm
Thank you everyone. I always learn something from all of you.
The only thing that I think "some" (not everyone) of you missed is this sentence from my OP

"Yes; I know that there are a myriad of ways to attack this problem. This example is for newbies."

Although many superior examples were demonstrated I posted this "Tip" in the Beginners section
for the purpose of
 1. Showing the BEGINNER how iterating over a string via a loop can go mysteriously(for him) wrong.
 2. Challenging the BEGINNER to discover why the unexpected (for him) error occurs.

As regards the sometimes heated debates here I think it is good to remember that
 1. English is not everyone's first language and shades of meaning as well as humor can be missed
 2. If we weren't pedantic before starting programming we certainly became so afterwards. ::)

Again; thank you everyone who contributed to the conversation. I will mark it as solved.

Klaatu Barada Nikto
Title: Re: [Solved] A Tip for beginners
Post by: silvercoder70 on January 20, 2025, 10:15:43 pm
The code I posted was only to show there is nothing inherently (?) wrong with using "to" to perform an operation.

The original poster was correct in respect to using Delete() when moving up vs down in a string. All I will say is ...

there are many ways to skin the [proverbial] cat (as the saying goes).
TinyPortal © 2005-2018