Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Anzahl von TStringList Items


ggehrma - Mi 14.09.05 16:07
Titel: Anzahl von TStringList Items
Hallo,

Ich habe eine TStringList in der einige Strings mehrmals vorkommen. Jetzt würde ich gerne wissen, welcher String wie oft in der Stringlist vorkommt.

Hat da jemand eine Idee, wie ich das anstellen kann?

mfg, ggehrma.

PS: Bitte keinen Code, sondern nur Gedankenanregungen.


Moderiert von user profile iconGausi: Topic aus VCL (Visual Component Library) verschoben am Mi 14.09.2005 um 16:20


Grishnak - Mi 14.09.05 16:14

Ansatz: Alle Strings über das .Text- oder .CommaText-Property auslesen und darin mittels PosEx suchen.


Gausi - Mi 14.09.05 16:19

Ich würde eine neue Struktur nehmen, in etwa


Delphi-Quelltext
1:
2:
3:
Stringmitzahl = class(TObject)
meinstring: string;
Anzahl: integer;


Dann anfangen die Stringliste durchzugehen. Dabei für jeden String überprüfen: "Habe ich den schon erfasst?" Wenn ja: Anzahl in dem entsprechenden Objekt erhöhen. Wenn nicht: Neues Object mit dem String erstellen, und in eine TObjectlist reinpacken.

Wahrscheinlich gehts auch einfacher und schneller. Ist nur ein Gedanke :wink:


ggehrma - Mi 14.09.05 17:12

Also .CommaText bringt mir nix, da es nix zu "CommaTexten" gibt. Hier mal ein Beispiel, wie meine Stringlist aussieht:

Eintrag String
0 a+bc0
1 e-fg-1
2 a+bc0
3 h+ij1
4 k-lm0
5 e-fg-1
6 a+bc0
7 n-op1

Und jetzt möchte ich halt wissen, wie oft z.B. der String a+bc0 vorkommt (hier wäre es ja 3mal).


Sprint - Mi 14.09.05 17:51


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function GetValueCount(AStrings: TStrings; const AValue: String): Integer;
var
  I: Integer;
begin

  Result := 0;
  for I := 0 to AStrings.Count - 1 do
    if AStrings.Strings[I] = AValue then
      Inc(Result);

end;


Das ist vielleicht nicht besonders effizient, sollte aber für kurze StringListen langen.


alzaimar - Mi 14.09.05 17:52

Tipp: Sortiere die Liste doch einfach und dann gehst Du von vorne nach hinten. Während des Durchlaufens prüfst Du, ob der aktuelle String S[i] = S[i-1] ist.


Grishnak - Mi 14.09.05 18:14

ggehrma hat folgendes geschrieben:
Also .CommaText bringt mir nix, da es nix zu "CommaTexten" gibt. Hier mal ein Beispiel, wie meine Stringlist aussieht:


der .CommaText würde nach deinem Beispiel so aussehen:

Quelltext
1:
'a+bc0,e-fg-1,a+bc0,h+ij1,k-lm0,e-fg-1,a+bc0,n-op1'                    


Jetzt gehst du alle Strings deiner Stringliste durch und suchst per PosEx in diesem .CommaText danach!


Lannes - Mi 14.09.05 22:38

Hallo,

diese Funktion gibt die Anzahl der Items aus,
mit dem Vorteil das die Original-Stringliste unsortiert bleibt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
function StrInStrList(s: String;sL: TStringlist): Integer;
var aStringList : TStringlist;
    pos,i : Integer;
begin
  aStringList := TStringlist.Create;
  try
    aStringList.Text := sL.Text;
    aStringList.Sort;
    pos := aStringList.IndexOf(s);
    if pos <> -1 then
      begin
      i := 1;
      while aStringList[pos+i] = s  do
        inc(i);
      result := i;
      end
      else
        result := 0;
  finally
    aStringList.Free;
  end;
end;


alzaimar - Mi 14.09.05 22:47
Titel: Re: Anzahl von TStringList Items
@Lannes: Jetzt hast Du ihm den Spass verdorben tzz tzz tzz.
user profile iconggehrma hat folgendes geschrieben:
...PS: Bitte keinen Code, sondern nur Gedankenanregungen.


UGrohne - Mi 14.09.05 22:56

Hab auch noch ne Anregung:

Also wenn es fuer etwas größeres sein sollte, dann wuerde ich wahrscheinlich eine Klassse von TStringList ableiten, die Add-Funktion ueberschreiben, ein Integer-Array hinzufügen (für die Anzahl) und beim Einfügen den Vorschlag von Gausi übernehmen. So hättest Du immer noch eine Klasse, aber mit allen Infos, die Du brauchst.


Lannes - Mi 14.09.05 23:13

Hallo,

@alzaimar: war nicht meine Absicht :oops:


alzaimar - Do 15.09.05 08:42

user profile iconUGrohne hat folgendes geschrieben:
Hab auch noch ne Anregung:
Also wenn es fuer etwas größeres sein sollte, dann wuerde ich wahrscheinlich eine Klassse von TStringList ableiten, die Add-Funktion ueberschreiben, ein Integer-Array hinzufügen (für die Anzahl) und beim Einfügen den Vorschlag von Gausi übernehmen. So hättest Du immer noch eine Klasse, aber mit allen Infos, die Du brauchst.

Jo, oder einfach Integer (MyStringList.Objects[x]) verwenden


ggehrma - Do 15.09.05 13:24

Hallo,

danke für eure vielen Vorschläge. Hab mir jetzt selber was zusammengebastelt, was aber doch auf vielem von dem, was ihr vorgeschlagen habt basiert.

Hier der Code (ist leider etwas aus dem Zusammenhang gerissen):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
PROCEDURE Auswertung(Formulierung: String);
BEGIN
  IF FormulierungsListe.IndexOf(Formulierung) = -1 THEN BEGIN
    FormulierungsListe.Add(Formulierung);
    Anzahl.Add('1');
  END
  ELSE
    Anzahl.Strings[FormulierungsListe.IndexOf(Formulierung)] := IntToStr(StrToInt(Anzahl.Strings[FormulierungsListe.IndexOf(Formulierung)])+1);
END;

FormulierungsListe und Anzahl sind zwei StringListen. Ich weiß, es geht sicherlich auch noch schöner. Aber das erschien mir so am einfachsten.

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt.


alzaimar - Do 15.09.05 14:03

So ist es schon ok. Hier noch mein Vorschlag:
Anstatt der separaten Liste 'Anzahl' kannst du ruhig die Objects-Eigenschaft der Stringliste benutzen.
Weiterhin wird der IndexOf nur 1x berechnet. Stell Dir vor, die Liste sei 100000000 Elemente lang, dann macht das schon viel aus.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
PROCEDURE Auswertung(Formulierung: String);
Var
  i : Integer;

BEGIN
  i := FormulierungsListe.IndexOf(Formulierung); 
  IF i = -1 THEN 
    FormulierungsListe.AddObject (Formulierung, Pointer (1));
  ELSE 
    Formulierungsliste.Objects[i] := Pointer (Integer (FormulierungsListe.Objects[i])
END;

Function Anzahl (i : Integer) : Integer;
Begin
  Result := Integer (Formulierungsliste.Objects[i])
End;