Toon posts:

[DELPHI] Random vraag!

Pagina: 1
Acties:

Verwijderd

Topicstarter
Heb stukje code wat ervoor moet zorgen dat alles wat in memo1 staat gehusseld in memo2 weer terecht moet komen.
code:
1
2
3
 randomize;
 for x := 0 to (memo1.lines.count -1) do
 memo2.lines[x] := memo1.lines[random(memo1.Lines.count)];

Dit werkt op zich maar mijn vraag is pakt hij elke memo line maar een keer? of komen er nu ook dubbele waarden in memo2? En pakt hij ze wel allemaal?

  • whoami
  • Registratie: December 2000
  • Laatst online: 20:22
Als je de lijn in Memo1 laat staan, bestaat de kans dat hij bepaalde rijen meerdere keren neemt, en andere rijen geen enkele keer.
Je kunt dus, als je een lijn hebt gegrabbed en in memo2 gezet, die lijn uit memo1 weghalen. (Dan ga je wel een while-lus moeten gebruiken ipv een for).
Of je kan ook bijhouden welke lijnen er al eens aan de beurt zijn geweest, en daar dan op testen.

https://fgheysels.github.io/


Verwijderd

Op donderdag 27 juni 2002 17:00 schreef EM het volgende:
Heb stukje code wat ervoor moet zorgen dat alles wat in memo1 staat gehusseld in memo2 weer terecht moet komen.
code:
1
2
3
 randomize;
 for x := 0 to (memo1.lines.count -1) do
 memo2.lines[x] := memo1.lines[random(memo1.Lines.count)];

Dit werkt op zich maar mijn vraag is pakt hij elke memo line maar een keer? of komen er nu ook dubbele waarden in memo2? En pakt hij ze wel allemaal?
Ik zou de waarde van het random getal tijdelijk opslaan zodat je die item later uit de memo1 kan verwijderen. Anders krijg je idd dubbele waarden en sommige zullen worden overgeslagen.

dus iets van:
code:
1
2
3
int rndGetal = random(memo1.Lines.count);
memo2.lines[x] = memo1.lines[rndGetal];
memo1.removeline[rndGetal];

Hoe het precies in delphi moet weet ik niet, maar dat zal je zelf wel weten.

Verwijderd

Topicstarter
code:
1
2
3
4
5
6
7
 randomize;
 for x := 0 to (memo1.lines.count -1) do
   begin
     Rdnmgetal := random(memo1.Lines.count);
     memo2.lines[x] := memo1.lines[Rdnmgetal];
     memo1.lines.Delete(Rdnmgetal);
   end;

Perfect, lekker simpel en toch functioneert het :)

edit:

Maar nu het volgende probleem

Verwijderd

Topicstarter
code:
1
2
3
4
5
6
7
8
9
randomize;
  for x := 0 to (memo1.lines.count -1) do
    begin
    Rdnmgetal := random(memo1.Lines.count);
    memo2.lines[x] := memo1.lines[Rdnmgetal];
    memo1.lines.Delete(Rdnmgetal);
    end;
memo1.lines :=  memo2.lines; 
memo2.lines.clear;

Na een keer geklikt te hebben staat in memo1 alles mooi door elkaar.
Klik ik echt nog een keer is memo1 in een keer geheel leeg? :? Me not snap....

  • Knutselsmurf
  • Registratie: December 2000
  • Laatst online: 00:05

Knutselsmurf

LED's make things better

Memo1.lines en memo2.lines zijn pointers, die je naar het zelfde stuk geheugen laat wijzen. Als je dan memo1.lines.clear doet, is dat allemaal weg. Maak van die memo1.lines:=memo2.lines maar eens memo1.lines.assign(memo2.lines). Volgens mij zou dat moeten werken. De assign maakt namelijk een kopie van de inhoud endat is precies datgene wat jij wilt.

- This line is intentionally left blank -


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 28-08 12:00

Janoz

Moderator Devschuur®

!litemod

Dit lijkt een beetje op het 'kaartenschud'-probleem. Zelf gebruik ik hiervoor altijd het volgende algoritme:
code:
1
2
  for (i=0 ; i<bepaald getal ; i++)
    swap (lijst[random],lijst[random]);

Eigenlijk gewoon twee random gekozen elementen met elkaar verwisselen. Als je zorgt dat het getal 'bepaald getal' van een juiste grote is (hangt af van het aantal elementen en de tijd die je eraan wilt besteden) zullen de kaarten goed geschud worden.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Op donderdag 27 juni 2002 18:59 schreef EM het volgende:
code:
1
2
3
4
5
6
7
8
9
randomize;
  for x := 0 to (memo1.lines.count -1) do
    begin
    Rdnmgetal := random(memo1.Lines.count);
    memo2.lines[x] := memo1.lines[Rdnmgetal];
    memo1.lines.Delete(Rdnmgetal);
    end;
memo1.lines :=  memo2.lines; 
memo2.lines.clear;

Na een keer geklikt te hebben staat in memo1 alles mooi door elkaar.
Klik ik echt nog een keer is memo1 in een keer geheel leeg? :? Me not snap....
mijn delphi is een beetje roestig, maar als je de laatste 2 regels veranderd naar het volgende, moet het wel lukken:
code:
1
2
3
for x := 0 to (memo2.lines.count -1) do
  memo1.lines[x] := memo2.lines[x];
memo2.lines.clear;

  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 23:25

Delphi32

Heading for the gates of Eden

Op donderdag 27 juni 2002 21:52 schreef Jappie het volgende:

[..]

mijn delphi is een beetje roestig, maar als je de laatste 2 regels veranderd naar het volgende, moet het wel lukken:
code:
1
2
3
for x := 0 to (memo2.lines.count -1) do
  memo1.lines[x] := memo2.lines[x];
memo2.lines.clear;
Gebruik de good old Assign methode:
code:
1
2
Memo1.Lines.Assign(Memo2.Lines);
Memo2.Lines.Clear;

Verwijderd

Topicstarter
code:
1
2
3
for x := 0 to (memo2.lines.count -1) do
  memo1.lines[x] := memo2.lines[x];
memo2.lines.clear;

Deze werkt helaas niet
code:
1
2
Memo1.Lines.Assign(Memo2.Lines);
Memo2.Lines.Clear;

En deze krijg ik precies hetzelfde als wat ik al had.....
Dit is dus niet de oplossing....

Verwijderd

Topicstarter
Heb denk ik de oplossing, tenminste werkt tot nu toe eindelijk:

De voorwaarde is dat de beide memo velden geen lines hebben als ze gegenereerd worden.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  randomize;
  for x := 0 to (memo1.lines.count -1) do
    begin
     Rdnmgetal := random(memo1.Lines.count);
     memo2.lines.Add(memo1.lines[Rdnmgetal]);
     memo1.lines.Delete(Rdnmgetal);
    end;

for x := 0 to (memo2.lines.count -1) do
  begin
    if memo2.lines[x] = '' then
    memo2.lines.Delete(x)
    else
    memo1.lines.add(memo2.lines[x]);
  end;
memo2.lines.clear;

Kan mischien simpeler maar het werkt en dat is het belangrijkste! Bedankt in ieder geval voor 'your cooperation"

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 20:41

Tomatoman

Fulltime prutser

Randomize hoeft maar één keer in je programma te worden aangeroepen. Meerdere keren heeft geen enkel nut. Goede plaats voor Randomize is bijvoorbeeld in de OnCreate van een form.

Een goede grap mag vrienden kosten.


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 23:01
Op vrijdag 28 juni 2002 17:23 schreef EM het volgende:
Kan mischien simpeler maar het werkt en dat is het belangrijkste! Bedankt in ieder geval voor 'your cooperation'
Het kan inderdaad simpeler, want je neemt het verkeerde uitgangspunt.

Jij leest steeds een willekeurige regel uit de bronlijst en die voeg je toe aan je doellijst. Hierbij kan je dus per ongeluk 2x dezelfde regel inlezen. Dit wordt hierna met allerlei omslachtige manieren teniet gedaan in de postings die volgen.

Een beter algoritme is om voor elke regel in je doellijst een willekeurige bestemming toe te wijzen. Op die manier bestaat er geen mogelijkheid om dubbelen te krijgen. In code wordt dat dan:
code:
1
2
3
  Voor elk element (var bron) uit de bronlijst doe
    Kies een willekeurig getal (var doel) tussen 1 en (aantal elementen in doellijst)
    Zet element(bron) op positie (doel) in doellijst

klaar.

Even uit mijn hoofd, zonder controles:
code:
1
2
3
4
5
  for bron:=0 to bronlijst.items.count-1 do
  begin
    doel=random(doellijst.item.count)
    doellijst.insert(doel,bronlijst.items(bron))
  end

PS: Sorry voor het omhoogtrappen van dit topic, maar soms blijkt dat een andere aanpak een stuk efficienter werkt. En een verse blik helpt soms om een andere manier te zien.

  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 23:25

Delphi32

Heading for the gates of Eden

Op vrijdag 12 juli 2002 17:25 schreef jvdmeer het volgende:

[..]

Het kan inderdaad simpeler, want je neemt het verkeerde uitgangspunt.

Jij leest steeds een willekeurige regel uit de bronlijst en die voeg je toe aan je doellijst. Hierbij kan je dus per ongeluk 2x dezelfde regel inlezen. Dit wordt hierna met allerlei omslachtige manieren teniet gedaan in de postings die volgen.

Een beter algoritme is om voor elke regel in je doellijst een willekeurige bestemming toe te wijzen. Op die manier bestaat er geen mogelijkheid om dubbelen te krijgen. In code wordt dat dan:
code:
1
2
3
  Voor elk element (var bron) uit de bronlijst doe
    Kies een willekeurig getal (var doel) tussen 1 en (aantal elementen in doellijst)
    Zet element(bron) op positie (doel) in doellijst

klaar.

Even uit mijn hoofd, zonder controles:
code:
1
2
3
4
5
  for bron:=0 to bronlijst.items.count-1 do
  begin
    doel=random(doellijst.item.count)
    doellijst.insert(doel,bronlijst.items(bron))
  end

PS: Sorry voor het omhoogtrappen van dit topic, maar soms blijkt dat een andere aanpak een stuk efficienter werkt. En een verse blik helpt soms om een andere manier te zien.
Ik heb je voorstel even zitten bekijken, en moet zeggen dat het niet oninteressant was wat je schreef. Twee vragen:

1.
code:
1
2
3
begin
  doel=random(doellijst.item.count)
end

En wat moet doel dan volgens jou worden, als er nog geen items in de doellijst zitten?

2. Geeft jouw methode dan garantie voor het niet voorkomen van dubbele entries in de DoelLijst? Ik zie nog niet waarom. Explain plz! Altijd bereid om te leren :)

  • Acid_Burn
  • Registratie: Augustus 2001
  • Laatst online: 21-08 11:09

Acid_Burn

uhuh

Die methode garandeerd niet dat je niet 2 keer dezelfde waarde krijgt. Hij trekt alleen een random waarde uit een steeds groter wordende 'pool'.

Wat zeker werkt is wat al eerder genoemd is, is de kaartschud methode. Kopieer eerst alle regels uit memo1 naar memo2 en verwissel dan elke keer 2 random regels met elkaar in memo2

Als je dit 2 of 3 maal het het aantal regels in de memo doet is het wel goed gehusseld :)

Deze methode zorgt ervoor dat je
a) zeker weet dat ALLE regels zijn gebruikt, immers ze staan allemaal al in memo2
b) zeker weet dat GEEN ENKELE regel dubbel gebruikt wordt, immers je hebt alleen maar zitten husselen in de gekopieerde data en er niks bij 'verzonnen' c.q. gekopieerd.
c) je hoeft niet te controleren of de regel waar je mee bezig bent al in de memo staat, zie b)

safe en simpel zullen we maar zeggen :)

Glass Eye Photography | Zelfbouw wireless fightstick | Mijn puzzel site


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15:34
Op zaterdag 13 juli 2002 01:51 schreef Acid_Burn het volgende:
Die methode garandeerd niet dat je niet 2 keer dezelfde waarde krijgt. Hij trekt alleen een random waarde uit een steeds groter wordende 'pool'.
De exacte implementatie klopt niet, (wat gedoe met plusjes en minnetjes en off-by-one enzo) maar de gedachte is wel goed. Elke waarde wordt precies één keer ingevoerd in de lijst met resultaten (en wel op een willekeurige plek in die lijst).
Wat zeker werkt is wat al eerder genoemd is, is de kaartschud methode. Kopieer eerst alle regels uit memo1 naar memo2 en verwissel dan elke keer 2 random regels met elkaar in memo2
Dat werkt, maar dan moet je wel vaker random aanroepen om een zelfde mate van randomness te krijgen en dan nog is de kans vrij groot dat er verhoudingsgewijs te veel items op hun plaats blijven staan.

Wel een voordeel van deze implementatie, is dat 'ie efficiënter is dan de meeste andere implementaties, maar dat hangt natuurlijk ook samen met het aantal verwisselingen dat je uitvoert.

  • Acid_Burn
  • Registratie: Augustus 2001
  • Laatst online: 21-08 11:09

Acid_Burn

uhuh

Ik had je voorbeeld verkeerd gelezen |:(

klopt wel.. je loopt memo1 regel voor regel af en insert em op een random plaats. Dus maar 1 keer n regels de random aanroepen. Helemaal gelijk :)

Glass Eye Photography | Zelfbouw wireless fightstick | Mijn puzzel site


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 20:41

Tomatoman

Fulltime prutser

Op vrijdag 12 juli 2002 17:25 schreef jvdmeer het volgende:
code:
1
2
3
4
5
  for bron:=0 to bronlijst.items.count-1 do
  begin
    doel=random(doellijst.item.count)
    doellijst.insert(doel,bronlijst.items(bron))
  end
Dit voorbeeld geeft GEEN random verdeling. Bronlijst.Items(0) komt altijd op positie 0 in de lijst binnen. Dan komt Bronlijst.Items(1), die op positie nul wordt geplaatst (want Random(1) = 0). Dan krijg je Bronlijst.Items(2), die wordt geplaatst op positie 0 of 1, maar nooit op positie 3. Immers: Random(2) = 0 of 1. Kortom, je moet een item op de positie Random(Doellijst.Items.Count +1) zetten:
code:
1
2
3
4
5
  for Bron: =0 to Bronlijst.Items.Count -1 do
  begin
    Doel := Random(Doellijst.Items.Count +1);
    Doellijst.Insert(Doel, Bronlijst.Items(Bron));
  end

En nu zou het moeten werken. Truc is dat je ook moet kunnen inserten op de positie achter het laatste item in Doellijst.

Een goede grap mag vrienden kosten.


  • jhksema
  • Registratie: Januari 2002
  • Laatst online: 28-08 17:17
Volgens mij kan het allemaal nog makkelijker:

Beschouw het idd als een kaartschud-probleem, maar ga niet telkens 2 kaarten omdraaien, want dan weet ik niet hoe vaak ik dit moet doen. Gebruik daarom de volgende oplossing (in pseudocode):
code:
1
2
3
4
5
6
7
  Gegeven een lijst L[1..n] met waarden.
  n':= n;
  for i:= 1 to n do {
    rnd = Random(1..n');
    Verwissel L[n'] en L[rnd];
    n'--;
  }

Schets correctheid:

Het element op plaats n heeft kans 1/n om hier te komen (functie Random geeft waarde uit uniforme verdeling).

Het element op plaats n-1 staat NIET op plaats n, met kans (n-1)/n;
Om WEL op plaats n-1 te staan moest het met kans 1/(n-1) worden getrokken. De kans om op positie n-1 te staan is dus:
(n-1)/n * 1 / (n-1) = 1/n.

Met inductie: iedere waarde staat met kans 1/n op iedere positie.

Omdat in iedere iteratie de nieuw te vullen positie vaststaat, komen dubbele waarden nooit voor. Omdat ik achteraan vul en vooraan kies kan ik binnen een lijst 'schudden'.

Iig is dit mijns inziens de manier om je probleem (efficient) op te lossen. Hoop dat je er wat mee kan...

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15:34
Op zaterdag 13 juli 2002 13:42 schreef jhksema het volgende:
Volgens mij kan het allemaal nog makkelijker:
Jouw oplossing komt in feite neer op die van jvdmeer (met de foutjes eruit), met het verschil dat jij de items 'in place' door elkaar husselt, terwijl jvdmeer's algoritme een tweede array gebruikt. In plaats van dat je de items in volgorde op een random plaats zet, zet je random items in volgorde op de vrije plaatsen. Het resultaat is inderdaad hetzelfde en ook correct.

Welk algoritme het meest geschikt is hangt voornamelijk af, van de vraag of je de originele array wilt behouden. jvdmeer's algoritme is algemener bruikbaar, omdat ook als je de originele array niet hoeft te behouden, het niet echt een probleem is als dit wel gebeurt.

Ik kies in de praktijk echter bijna altijd voor jouw oplossing.

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 23:01
Op zaterdag 13 juli 2002 14:18 schreef Soultaker het volgende:
Welk algoritme het meest geschikt is hangt voornamelijk af, van de vraag of je de originele array wilt behouden. jvdmeer's algoritme is algemener bruikbaar, omdat ook als je de originele array niet hoeft te behouden, het niet echt een probleem is als dit wel gebeurt.
Als je de allereerste posting leest, dan zal je zien dat de OP gebruik wil maken van 2 arrays:
Op donderdag 27 juni 2002 17:00 schreef EM het volgende:
Heb stukje code wat ervoor moet zorgen dat alles wat in memo1 staat gehusseld in memo2 weer terecht moet komen.

Verwijderd

Kijk eens naar het type TList in Delphi
Pagina: 1