Wybór z listboxa elementów - randomize

0

Mam taki problem do rozwiązania. W listbox znajdują się następujące wartości np :
W listbox mogą znajdować się wiecej lub mniej wartości.

a
b
c
d
e
f
g
h
1
5
g

Teraz chcę zaznaczyć znakiem * np 5 wartości od początku (randomize) tak aby inteligentnie
rozłożyły się znaki * im niżej tym mniej.

a *
b *
c 
d *
e *
f 
g
h *
1
5
g

Dla 20 wartości w listbox chce zaznaczyć 15 elementów np.

a *
b *
c *
d *
e 
f *
g *
h *
1 *
5 *
g *
m
6 *
7 *
r 
w *
k *
.
! *
p

Jak to zrobić ?

dodanie znaczników <code> - fp

0

ListBox ma wlaściwość multiselect, jeżeli ustawisz ją na true to możesz zaznaczać normalnym selectem.

  ListBox1.Selected[0]:=true;
  ListBox1.Selected[2]:=true;
  ListBox1.Selected[4]:=true;
0

_13th_Dragon wszystko rozumie. Chce jednak wybierać to programowo używając losowości. Pozdrawiam.

0
// Usun duplikaty z listy kod zaczerpniety z interneu
procedure RemoveDuplicates(const stringList : TStringList) ;
 var
   buffer: TStringList;
   cnt: Integer;
 begin
   stringList.Sort;
   buffer := TStringList.Create;
   try
     buffer.Sorted := True;
     buffer.Duplicates := dupIgnore;
     buffer.BeginUpdate;
     for cnt := 0 to stringList.Count - 1 do
       buffer.Add(stringList[cnt]) ;
     buffer.EndUpdate;
     stringList.Assign(buffer) ;
   finally
     FreeandNil(buffer) ;
   end;
 end;

var
 sl, sl1, sl2 : TStringList;
 cnt, i : integer;
 s : string;
begin
  s := InputBox('Wybierz elementy z listy', 'Podaj proszę ilość elementów !!!', s);
  if s = '' then exit;

  ListBox2.Clear;

  i := 0;
  Randomize;
  sl := TStringList.Create;
  sl1 := TStringList.Create;
  sl2 := TStringList.Create;

  sl1.Text := ListBox1.Items.Text;

  repeat

    i := Random(sl1.Count);
    sl2.add(sl1[i]);

    sl := TStringList.Create;
    for cnt := 0 to sl2.Count - 1 do
    sl.Add(sl2[cnt]);
    RemoveDuplicates(sl);

    for cnt := sl.Count - 1 downto 0 do
    if sl[cnt] = '' then sl.Delete(cnt);

    sl2.Assign(sl);

    sl.Free;

  until

    sl2.Count  = strtoint(s);

    Label4.Caption := inttostr(sl2.Count);

    ListBox2.Items.Text := sl2.Text;
     
    sl.Free;
    sl1.Free;
    sl2.Free;

To jest kod który losuje z całej listy a mi chodzi żeby losował zagęszczając na poczatku.

0
var Rnd,Sum:Double;
var More:Boolean;
var I,L,Max:Integer;
begin
  Max:=ListBox1.Items.Count-1;
  Sum:=0;
  for I:=0 to Max do
  begin
    Sum:=Sum+Sqr(I+1);
    ListBox1.Selected[I]:=false;
  end;
  for L:=Max-5 downto 0 do
  begin
    More:=true;
    while More do
    begin
      Rnd:=Sum*Random;
      for I:=0 to Max do
      begin
        Rnd:=Rnd-Sqr(I+1);
        if Rnd<=0 then
        begin
          if not ListBox1.Selected[Max-I] then
          begin
            ListBox1.Selected[Max-I]:=true;
            More:=false;
          end;
          break;
        end;
      end;
    end;
  end;
end;

Zamiast Sqr można użyć dowolnej innej funkcji.

Tak a propos, nie grzeb w śmietnikach bo znajdziesz śmieci:

// Usun duplikaty z listy kod zaczerpniety z głowy, z tym że tego nie potrzebujesz
procedure RemoveDuplicates(stringList:TStringList);
begin
  stringList.Sorted:=true;
  stringList.Duplicates:=dupIgnore;
  stringList.Text:=stringList.Text;
end;
0

_13th_Dragon dziękuję bardzo o to mi właśnie chodziło. A powiedz co bym musiał zmienić aby losowanie odbywało się od końca i od środka ?

0

Ogólnie rzecz biorąc musisz przypisać każdej pozycji pewną liczbę która będzie działać jak współczynnik prawdopodobieństwa.
Najprościej to zrobić za pomocą jakiejś funkcji, w podanym powyżej przykładzie jest to funkcja: Sqr(I+1); odwrócona przez: [Max-I]

0

Mam kolego do Ciebie pytanie.
W listbox są pewne wartości i chcę teraz aby do listboxa2 skopiowały się te wartości z
założeniem, że 2 elementy będą kopiowane + 1 przerwa.

a *
b *
c
d *
e *
f
g *
h *
1
5 *
g *
j
h

czyli w listbox2

a
b
d
e
g
h
5
g

dodanie znaczników <code> - fp

0

A masz je jakoś zaznaczone (przez właściwość Selected)? W ogóle są jakoś zaznaczone? Bo jeśli tak, to wystarczy w pętli od 0 do Count - 1 sprawdzać czy są zaznaczone i skopiować je;

Jeśli nie masz ich zaznaczonych, to wystarczy nieco inna pętla, która skopiuje dwa, trzeci pominie i skoczy do kolejnej iteracji pętli, np:

var
  I: Integer;
begin
  I := 0;

  while I < ListBox1.Count - 1 do
  begin
    ListBox2.Items.Add(ListBox1.Items[I]);
    ListBox2.Items.Add(ListBox1.Items[I + 1]);
    Inc(I, 3);
  end;
end;

Ustawienie górnej granicy pętli zależy od tego czy może być skopiowany ostatni element listy, czy musi pozostać nieskopiowany co najmniej jeden.

0

A jeszcze pytanko jak w tym kodzie podstawić zmienne. np.:
Z = 4; // zaznaczone
N = 3 // niezaznaczone

z zabezpieczeniem przed wywołaniem wątku. Dla dwóch zaznaczonych i jednej pominiętej działa super. Jednak chciałbym wybierać ze zmiennych.

0

@Bruno(M) - no to raz pytasz o losowe kopiowanie, potem o statyczne, teraz znów jakieś inne...

var
  intCheckedCnt, intUncheckedCnt, I, J: Integer;
begin
  intCheckedCnt := 3;
  intUncheckedCnt := 2;
  I := 0;

  while I < ListBox1.Count do
  begin
    J := I;

    while J < I + intCheckedCnt do
    begin
      ListBox2.Items.Add(ListBox1.Items[J]);
      Inc(J);
    end;

    I := J + intUncheckedCnt;
  end;
end;

Wyjście:

0            0
1            1
2            2
3            .
4     ->     .
5            5
6            6
7            7
8            .
9            .

O takie coś chodzi...? Pokombinuj coś sam...

z zabezpieczeniem przed wywołaniem wątku.

Wyjątku, nie wątku; Wyjątek będzie wywołany jeśli spróbujesz uzyskać wartość spoza zakresu (która nie istnieje); Jeśli dobrze ustawisz pętle to tego wyjątku nie zobaczysz.

0

Tak dziękuję bardzo. Pokombinuje :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1