Link to home
Start Free TrialLog in
Avatar of Dsys
Dsys

asked on

Compare contents of TStringLists?

I have two  TStringlists.

  S : Integer;
  PlayList : TStringList;
  strList  : TStringList
.
.
.
  Randomize;
  S := Random(strList.Count);

  if S <= fileA then  begin
    PlayList.Add(strList[S]);
  end;

How can I perform this kind of check?

  if S {is within PlayList} then
     dothis
  else
     dothat
Avatar of zebada
zebada

It doesn't make sense to compare S (an integer) to PlayList (a TStringList).

Or do you want to know if 0<=S<PlayList.Count ?

Or do you mean how can you find out if the value strList[S] is in playList then just use:

playList.IndexOf(strList[S]);

It will return -1 for not found or the index number of the first matching value if it is found.
Nasty way would be to iterate through PlayList in a loop, checking each item. A better way is to try something like this (it is however case sensitive and only handles exact matches:

IF PlayList.IndexOf(S) <> -1
THEN
  //Item found
ELSE
  //Item NOT found

The Neil =:)
Avatar of Dsys

ASKER

can you show me the nasty way of testing by iterating through PlayList in a loop, checking each item...

i tried this:

//check
IF PlayList.IndexOf(strList[S]) <> -1 THEN
  load; //song has been played load new one.
else
  Play;

the if test always finds items in playlist even when it should not. See this code below gets run before the check.

//load
Randomize;
S := Random(strList.Count);
if S <= fileA then  begin
   PlayList.Add(strList[S]); //add one item.
end;
check;

playlist gets filled one item at a time. Where as strList is completely full of items at the begining. As playlist grows I want to skip items in it.
Ok, try this:

  FUNCTION ItemInData(sValue : STRING; stlData ; TSTringList): BOOLEAN;
  VAR
    iCount : LONGINT;
  BEGIN
    Result := FALSE;
    FOR iCount := 0 TO (stlData.Count - 1)
    DO
      IF stlData[iCount] = sValue
      THEN
        Result := TRUE;
  END;

Then all you need to do is call the function in your IF statement:

IF ItemInData(S, PlayList)
THEN
  //Item found
ELSE
  //Item not found
 
This will check every item in the list with the item you want to search for. If it constantly returns TRUE (ie it finds it) then there must be a problem with the data in PlayList

The Neil =:)
Avatar of Dsys

ASKER

This does not work.

FUNCTION TfrmMain.ItemInData(sValue : STRING; stlData : TStringList): BOOLEAN;
VAR
   iCount : LONGINT;
BEGIN
   Result := FALSE;
   FOR iCount := 0 TO (stlData.Count - 1)  DO
     IF stlData[iCount] = sValue  THEN  <===Error in Line
       Result := TRUE;
END;

.
.
.
 IF ItemInData(inttostr(S), PlayList) THEN
    PickSong;


I have to compare the item number it could be items 1 to 10000. The number I compare is not a count, it is a list index number. That is why this always fails to find items in the list.
Avatar of Dsys

ASKER

This works better.

Function TfrmMain.ItemInData(sValue : String; stlData : TStringList): BOOLEAN;
Var
   i : LONGINT;
   x : String;
Begin
   Result := FALSE;
   For i := 0 To (stlData.Count - 1)  Do begin
     x := stlData[i];
     If x = strList[S]  Then
       Result := True;
   end;
end;

except when it gets to the last members of the list. Then the loop befome infinate. Might there be a way to end the loop if that becomes the case?
This'll work better. It still loops through the data but it'll drop out as soon as it finds the item:

Function TfrmMain.ItemInData(s : LONGINT; stlData : TStringList): BOOLEAN;
VAR
  i : LONGINT;
  sItem : STRING;
BEGIN
  Result := FALSE;
  sItem := strList[S];
  i := 0;
  WHILE NOT(Result) AND (i < stlData.Count)
  DO
    IF stlData[i] = sItem
    THEN
      Result := True
    ELSE
      i := i + 1;
END;

Alternatively just go back to using IndexOf:

IF stlData.IndexOf(strList[S]) = -1
THEN
  //Not found
ELSE
  //Found

Being an idiot I didn't realise that S was an index into the list

The Neil =:)
Avatar of Dsys

ASKER

Cool... I will try this when I get home. The one other issue I ran into was this. When all items have been played and there for all songs are in playList, the check procedure becomes into an infinate loop.

I tried using a really stupid idea... using a global variable and incrementing it if the variable hit 2000 I figure that would be big enough to show that it is infinate, then I use an if statement to run application.terminate; This however does not really close the program gracefully. What do you think I should do?
Why not just check to see if there are all the items in the playlist as there are in the track list? BUT, rather than checking each item, cheat and do this:

IF strList.Count = PlayList.Count
THEN
  //All items played

This of course assumes that a track will only be played once. If it can be played more than once then you need to check it using something like this:

FUNCTION AllItemsPlayed(stlPlayList, stlTrackList : TStringList): BOOLEAN;
VAR
  stlTemp : TStringList;
  iCount : LONGINT;
BEGIN
  Result := TRUE;
  stlTemp := TStringList.Create;
  TRY
    FOR iCount := 0 TO (stlPlayList.Count - 1)
    DO
      IF stlTemp.IndexOf(stlPlayList[iCount]) = -1
      THEN
        stlTemp.Add(stlPlayList[iCount]);

    Result := (stlTemp.Count = stlTrackList.Count);
  FINALLY
    stlTemp.Free;
  END;
END;

This is the same check but it makes sure that each item in the playlist only gets 'counted' once by creating a temporary list containing a single entry for each item

The Neil =:)
Avatar of Dsys

ASKER

Maybe it should write the contents of playlist out to a txt file? so that when the program is launched again it can load the txt file and continue to not repeat. when the list is full prompt to delete the file.
ASKER CERTIFIED SOLUTION
Avatar of TheNeil
TheNeil

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Dsys

ASKER

My internet is down... I will try this and let you know how it all goes, thank you for all your help.

Avatar of Dsys

ASKER

gFile : TEXT; <--- this line give and error. does it require a certain uses?

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
No, it's standard Pascal. Just move it to the global variable declarations and it should work fine

The Neil =:)
Avatar of Dsys

ASKER

ok.. works as global but the file does not get written with:

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
var
  icount : integer;
begin

  AssignFile(gFile, 'c:\playlist.txt');
  ReWrite(gFile);
  FOR iCount := 0 TO (PlayList.Count - 1) DO <-- says count =0 ?
    WRITELN(gFile, PlayList[iCount]);

  CloseFile(gFile);
end;
Well the code SHOULD be working (and yes, the counter should run from 0 - Stringlists are zero based). Have you tried stepping through the code to see what is stored in the playlist? You're not doing something stupid like freeing the playlist before you reach this point are you?

The Neil =:)
Avatar of Dsys

ASKER

TheNeil,

No that is what I thought too. But I will work on it. I dont want to push this question too much further. You have been very helpful and I thank you!
Anytime you want to bounce a question then just post it

The Neil =:)