Archief - Irritant extra spatie probleem

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

FredWP

Legacy Member
Dit probleem ben ik al vaak in programma's tegen gekomen, maar tot nu alleen maar in test programma's dus had nooit moeite gedaan om het op te lossen.

Ik ervaar dit momenteel in een iets wat groter programma maar ik ga het demonstreren in een voorbeeld.

Stel je laat getallen naar een scherm uitvoeren en tussen elke uitkomst wil je een spatie zetten. Ik zou dit zo doen:

Code:
for (int i = 0; i <= 5; i++)
{
    txtOutput.Text += i + " ";
}
Uitvoer: 0(spatie)1(spatie)2(spatie)3(spatie)4(spatie)5(spatie)

Hoe los ik het extra spatie probleem op op het einde?

Code:
            // Apply the output again, but with one character less, solving the issue
            txtOutput.Text = txtOutput.Text.Substring(0, txtOutput.Text.Length - 1);
Uitvoer: 0(spatie)1(spatie)2(spatie)3(spatie)4(spatie)5

Mijn vraag is nu, is dit een goede manier? Ik denk dat het een slordige manier is, maar ik heb niet genoeg ervaring om daar over te oordelen, dus zou ik graag wat advies willen.

forloRn_

Legacy Member
String.substring() is een oplossing. Een if-clause binnen de loop heb ik ook al binnen de JDK gezien. In Java is Strings concateneren in een loop is niet echt performant, dus in de praktijk ga je vóór de loop een StringBuilder declareren, binnen de loop appenden en na de loop StringBuilder.delete() doen.

Whatever floats your boat dus.

Moto

Legacy Member
C# Project waar ik nu mee bezig ben hebben we een utils classke met volgende functie

Code:
      public static string Join(string separator, IEnumerable values)
      {
         StringBuilder sb = new StringBuilder();
         foreach (object o in values)
         {
            sb.Append(o == null ? "" : o.ToString());
            sb.Append(separator);
         }
         if (sb.Length != 0)
         {
            sb.Remove(sb.Length - separator.Length, separator.Length);
         }
         return sb.ToString();
      }

Gurdt

Legacy Member
forloRn_ zei:
String.substring() is een oplossing. Een if-clause binnen de loop heb ik ook al binnen de JDK gezien. In Java is Strings concateneren in een loop is niet echt performant, dus in de praktijk ga je vóór de loop een StringBuilder declareren, binnen de loop appenden en na de loop StringBuilder.delete() doen.

Whatever floats your boat dus.
een if-clause lijkt me niet zo nuttig, gezien ge dan iedere lus die if-test moet evalueren, tis maar 1 test, maar we willen streven naar efficiente code he ;)

als het een lineaire lus is (daarmee bedoel ik dat uw iterator altijd +1 ofzo is) en ge weet wanneer die gaat stoppen (op een bepaald getal of een variabele) kunt ge 1 lus vroeger stoppen, en na de for-structuur, nog 1 keer die lus uitvoeren

het is een beetje indisch maar met een sub-functie kunt is da nog cva op te lossen

Code:
//ge wilt een forlus van 1 tot en met N bv:
for( int i = 1; i <= N - 1; i++)
{
    //operatie, kan ook een functie zijn als die te lang wordt
    ...
    //separator-operatie
    string += " "; //ofzo
}
//operatie, met een variabele gelijk aan N als die nodig is
...

in het stukje code vn de threadstarter zou dat dus geven:
Code:
int n = 5;

for (int i = 0; i <= n - 1; i++)
{
    txtOutput.Text += i + " ";
}
txtOutput.Text += n;

Yngwie

Legacy Member
Gurdt, je streeft naar efficiente code maar je introduceert wel code duplication. Voor één regel gaat dat nog (al is het niet echt proper) maar vanaf je logica binnen de loop langer wordt dan één regel wordt het onoverzichtelijk.

Ook in je aangepaste code voor de treadstarter zit een fout. je gaat 5x je loopcode uitvoeren + nog een 6de keer na de loop terwijl er maar 5x zou mogen uitgevoerd worden.

ofwel for(int i = 0; i < n-1; i++)
ofwel for(int i = 0; i <=n; i++)
lost dit probleem op maar dan zit je nog altijd met die code duplication.

imo is het het beste van alle iteraties volledig te doorlopen en achteraf na de loop de ongewenste extra spatie te verwijderen.

Gurdt

Legacy Member
Yngwie zei:
Gurdt, je streeft naar efficiente code maar je introduceert wel code duplication. Voor één regel gaat dat nog (al is het niet echt proper) maar vanaf je logica binnen de loop langer wordt dan één regel wordt het onoverzichtelijk.

Ook in je aangepaste code voor de treadstarter zit een fout. je gaat 5x je loopcode uitvoeren + nog een 6de keer na de loop terwijl er maar 5x zou mogen uitgevoerd worden.

ofwel for(int i = 0; i < n-1; i++)
ofwel for(int i = 0; i <=n; i++)
lost dit probleem op maar dan zit je nog altijd met die code duplication.

imo is het het beste van alle iteraties volledig te doorlopen en achteraf na de loop de ongewenste extra spatie te verwijderen.
gij gaat 2 keer volledig de mist in

1) de threadstarter gaat wel degelijk 6 keer door de code:
for( int i = 0; i <= 5; i++ )

2) ik zeg net, ge kunt evengoed de inhoud vn die forlus in een functie steken, dan hebt ge géén code duplication (wat natuurlijk pas interessant is vanaf een bepaald aantal regels)

nog iets?

--
EDIT: je gaat voor de 3e keer de mist in:
ofwel for(int i = 0; i < n-1; i++) is NIET equivalent aan
ofwel for(int i = 0; i <= n; i++)

juist zou zijn:
ofwel for(int i = 0; i <= n-1; i++)
ofwel for(int i = 0; i < n; i++)
--
maar dit is alleen van toepassing wanneer uwen i altijd +1 is natuurlijk

Obliv`

Legacy Member
Gurdt zei:
tis maar 1 test, maar we willen streven naar efficiente code he ;)

Code:
//ge wilt een forlus van 1 tot en met N bv:
for( int i = 1; i <= N - 1; i++)
{
    //operatie, kan ook een functie zijn als die te lang wordt
    ...
    //separator-operatie
    string += " "; //ofzo
}
//operatie, met een variabele gelijk aan N als die nodig is
...

Als je toch efficiënte code wil schrijven, ga dan aub niet bij elke iteratie een nieuwe string aanmaken he ...

Gebruikt een stringbuilder met een size van uw N -1.
Of gebruik de string.Join method die achter de schermen maar één string zal alloceren en een charbuffer zal gebruiken om die string op te vullen.

Yngwie

Legacy Member
1) idd, voor die 6keer ipv 5 keer zit ik fout. Aangezien ik n = 5 bovenaan de code zie staan nam ik aan dat er ook 5 keer geïtereerd moet worden (logisch?)

2) ik blijf nog altijd bij mijn punt dat het niet echt proper is van 1x minder door u iteratie te lopen om na de loop nog eens de loopcode uit te voeren (ook al is het maar één functiecall)

3) daar hebt ge gelijk in maar daar is het ook duidelijk te zien dat het om een typo gaat

Ice

Legacy Member
Code:
for (int i = 0; i <= 5; i++)
{
   if (i > 0 ) {txtOutput.Text += " ";}
    txtOutput.Text += i;
}

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

Waarom het altijd nodeloos complex maken?

Obliv`

Legacy Member
Yngwie zei:
2) ik blijf nog altijd bij mijn punt dat het niet echt proper is van 1x minder door u iteratie te lopen om na de loop nog eens de loopcode uit te voeren (ook al is het maar één functiecall)

Ik geef u gelijk, maar wil wel vermelden dat in de code van het .NET Framework dit principe ook op verschillende plekken wordt toegepast.

Als je er een vertragend if-statement mee kunt vermijden, vind ik dat het wel moet kunnen om de laatste iteratie buiten de loop te doen.

Gurdt

Legacy Member
das idd vrij indisch, ma efficiëntie moet soms hand in hand gaan daarmee :D

forloRn_

Legacy Member
Ice heeft een punt hoor, Knuth trouwens ook. Je moet natuurlijk altijd je gezond verstand gebruiken als je programmeert maar leesbare code schrijven is nog altijd belangrijker dan die paar nanoseconden die je wint. Het hangt allemaal van de toepassing af maar in de meeste gevallen maakt het gewoon geen lor uit. Ik zou in ieder geval meer wakker liggen van deftig OO-design dan van efficiënt strings aan elkaar plakken.

Indisch :D. It's funny 'cause it's true.

killgore

Legacy Member
Gurdt zei:
een if-clause lijkt me niet zo nuttig, gezien ge dan iedere lus die if-test moet evalueren, tis maar 1 test, maar we willen streven naar efficiente code he ;)

uw processor optimaliseert dat weg in principe.

Die if gaat dus in het niets vallen in vergelijking met uw string concatenatie en eventuele cache missers.

Of: luister naar ice :-).

SavaB

Legacy Member
ik veronderstel dat txtOutput een string is? een string is niet veel meer dan een vector van chars, met evt iets andere functionaliteiten.
dus: voeg achteraf gwn txtOutput.erase(txtOutput.size()-1); toe, en je bent de spatie aan het einde kwijt.

btw, probeer ++i in je lus te gebruiken, ipv i++. (nu we toch over efficiente code bezig zijn)

killgore

Legacy Member
SavaB zei:
btw, probeer ++i in je lus te gebruiken, ipv i++. (nu we toch over efficiente code bezig zijn)

ik geloof mijn ogen niet denk ik. wtf zou da helpen :p.

Gurdt

Legacy Member
killgore zei:
ik geloof mijn ogen niet denk ik. wtf zou da helpen :p.

helpt idd geen aars, het verschil tussen ++i en i++ is dit:

++i gaat eerst i incrementeren (+1) en dan het resultaat returnen
i++ gaat eerst i 'saven' en dan pas incrementeren, en dan het gesavede returnen

voorbeeld:
int i = 5;
int j = ++i; //j = 6 en i = 6
int k = i++; //k = 6 en i = 7

maar in een opdracht waarbij niks gereturnd wordt is er geen verschil tussen i++ en ++i, de returnwaardes zijn wel verschillend, maar doen er niet toe...
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan