AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Dateiliste gefiltert erstellen

Ein Thema von DieDolly · begonnen am 24. Aug 2023 · letzter Beitrag vom 24. Aug 2023
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#11

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 17:37
HashListe oder einfach nur eine sortierte Liste ... da lässt sich schneller finden,
selbst wenn man eine TStringList benutzt.

TStringList.Sorted=True und TStringList.IndexOf
TDictionary<>
TArray<string> mit TArray.BinarySearch<string> (zum Suchen, aber auch zum "sortierten" Einfügen), bzw. TArray.Sort<string>
...



EndsText kann ich nicht nehmen, weil ein FileX.exe in der Filterliste gilt nur im Hauptverzeichnis, nirgendwoanders.
Dann mußt du wohl deine Pfade zu RelativenPfaden machen.
und dann kannst'e mit MatchText oder TArray.BinarySearch oder

Delphi-Referenz durchsuchenExtractRelativePath
Delphi-Referenz durchsuchenTPath.IsPathRooted
siehe https://docwiki.embarcadero.com/RADS...ation_Routines
oder

oder ReplaceStr ähhh ReplaceText(FullFileName, 'C:\root\', '') [b][\b]
oder Delete(FullFileName, 1, Length('C:\root\')); (natrürlich aufpassen, falls nicht in diesem Pfad)
oder ...


https://stackoverflow.com/questions/...aths-in-delphi
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (24. Aug 2023 um 17:40 Uhr)
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#12

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 17:46
Da sind mir zu viele "oder" in dem Text. Zuviel Stress. Ich lasse alles so wie es ist

Geändert von DieDolly (24. Aug 2023 um 17:55 Uhr)
  Mit Zitat antworten Zitat
tomkupitz

Registriert seit: 26. Jan 2011
323 Beiträge
 
Delphi 11 Alexandria
 
#13

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 17:48
Zitat:
Weil Wenn Liste A 15.000 Einträge hat und B 1000, sind das, wenn man jeden Eintrag mit jedem vergleicht, sehr viele Vergleiche, viele davon mehr als unnötig.
Aber diese unnötigen Vergleiche verhinders du ja mit der HashListe.

vorhanden:

ListeB

File20
..
File30

von ListeB HashListe erstellen (oder gleich als Hash halten)


---

wird geade erstellt:

ListeA

File1 -> HashIndex berechnen und in ListeB im Index gucken => nicht da, kann in ListeA bleiben
..
File20 - HashIndex berechnen und in ListeB im Index gucken -> vorhanden, kann aus ListA raus
..
File100

ggf. Dateiname und Pfad wie oben erwähnt trennen und bei Vergleich nutzen.

Deine Suche dauert zu lange.
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#14

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 17:56
Ich kann nicht auf eine HashListe umstellen. Das geht einfach nicht mehr...

Wie sähe denn ein kleines Beispiel aus basierend auf Winapi.Windows.FindFirstFileEx()?

Vielleicht kann ich das anders lösen, ohne vorhandenen Code groß abändern zu müssen.
Meine Idee:
- Mit Winapi.Windows.FindFirstFileEx() Liste A erstellen und in HashListe packen.
- Liste B in HashListe packen (die steht in einer Textdatei).
Beide vergleichen.

Mit dem Rest von Liste A die Objekte erstellen.

Aber ich kann mir nicht vorstellen, wie das mit der HashListe funktioniert.

Meinst du sowas? https://www.delphipraxis.net/1159090-post3.html

Geändert von DieDolly (24. Aug 2023 um 18:04 Uhr)
  Mit Zitat antworten Zitat
tomkupitz

Registriert seit: 26. Jan 2011
323 Beiträge
 
Delphi 11 Alexandria
 
#15

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 18:43
Beispiel mit Kollisionsprüfung (verkettete Liste):

Code:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  THashItem = class(TObject)
  public
    Key: string;

    Next: THashItem;
  end;

  THashList = class(TObject)
  private
    FItems: array of THashItem;

    function GetCount: Integer;
    function GetItem(Index: Integer): THashItem;
  public
    constructor Create(Count: Integer);
    destructor Destroy; override;

    function CreateHash(AKey: string): Integer;

    function Add(AKey: string): Boolean;
    procedure Clear;

    function Find(AKey: string): Integer;

    property Count: Integer read GetCount;
    property Items[Index: Integer]: THashItem read GetItem;
  end;

  TForm1 = class(TForm)
    ListBox1: TListBox;
    ListBox2: TListBox;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor THashList.Create(Count: Integer);
begin
  inherited Create;

  SetLength(FItems, Count);
end;

destructor THashList.Destroy;
begin
  Clear;

  Finalize(FItems);

  inherited Destroy;
end;

//

function THashList.GetCount: Integer;
begin
  result:=Length(FItems);
end;

function THashList.GetItem(Index: Integer): THashItem;
begin
  if (Index>-1) and (Index<Length(FItems)) then
    result:=FItems[Index]
  else
    result:=nil;
end;

//

function THashList.Add(AKey: string): Boolean;
var i: Integer;

    Item: THashItem;

begin
  i:=CreateHash(AKey);

  if (i>-1) and (i<Length(FItems)) then
  begin
    if FItems[i]=nil then
    begin
      FItems[i]:=THashItem.Create;
      FItems[i].Key:=AKey;
    end;

    Item:=FItems[i];

    while Item.Key<>AKey do
    begin
      if Item.Next=nil then
      begin
        Item.Next:=THashItem.Create;
        Item.Next.Key:=AKey;
      end;

      Item:=Item.Next;
    end;

    if Item.Key=AKey then
    begin
      result:=True;
      Exit;
    end
  end;

  result:=False;
end;

procedure THashList.Clear;
var i: Integer;

    Item, Next: THashItem;

begin
  for i:=0 to High(FItems) do
    if FItems[i]<>nil then
    begin
      Item:=FItems[i];

      while Item<>nil do
      begin
        Next:=Item.Next;

        Item.Free;

        Item:=Next;
      end;

      FItems[i]:=nil;
    end;
end;

//

function THashList.Find(AKey: string): Integer;
var i: Integer;

    Item: THashItem;

begin
  i:=CreateHash(AKey);

  if (i>-1) and (i<Length(FItems)) then
  begin
    Item:=FItems[i];

    while (Item<>nil) and (Item.Key<>AKey) do
      Item:=Item.Next;

    if (Item<>nil) and (Item.Key=AKey) then
    begin
      result:=i;
      Exit;
    end;
  end;

  result:=-1;
end;

//

function THashList.CreateHash(AKey: string): Integer;
var i: Integer;

begin
  result:=-1;

  if Length(AKey)=0 then
    Exit;

  result:=ord(AKey[1]) mod Length(FItems);

  for i:=2 to Length(AKey) do
    result:=(result*128+ord(AKey[i])) mod Length(FItems);
end;

//

var
  hl: THashList;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;

begin
  hl:=THashList.Create(50);

  //ListeB

  for i:=20 to 30 do
    hl.Add('File'+IntToStr(i));

  //ListeA

  for i:=0 to 100 do
    if hl.Find('File'+IntToStr(i))=-1 then
      ListBox1.Items.Add('File'+IntToStr(i))
    else
      ListBox2.Items.Add('File'+IntToStr(i));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  hl.Free;
end;

end.

###
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 433
  ClientWidth = 622
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -12
  Font.Name = 'Segoe UI'
  Font.Style = []
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  TextHeight = 15
  object Label1: TLabel
    Left = 32
    Top = 24
    Width = 32
    Height = 15
    Caption = 'ListeA'
  end
  object Label2: TLabel
    Left = 247
    Top = 24
    Width = 31
    Height = 15
    Caption = 'ListeB'
  end
  object ListBox1: TListBox
    Left = 32
    Top = 56
    Width = 209
    Height = 329
    ItemHeight = 15
    TabOrder = 0
  end
  object ListBox2: TListBox
    Left = 247
    Top = 56
    Width = 209
    Height = 329
    ItemHeight = 15
    TabOrder = 1
  end
end
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#16

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 18:57
Ich habe das jetzt etwas anders gemacht. Mittels Winapi.Windows.FindFirstFileEx() hole ich mir alle Dateien und füge die in einen HashTable ein der so deklartiert ist
Delphi-Quellcode:
type
 TFileHashTable = TDictionary<string, TWin32FindData>;

var FileHashTable: TFileHashTable;

// hinzufügen
FileHashTable.Add(RootFolder + lfdStruct.cFileName, lfdStruct);
So hole ich Einträge die in Liste B sind aus Liste A raus
Delphi-Quellcode:
for i := 0 to ListeB.Count - 1 do
 begin
  if not FileHashTable.ContainsKey(RootFolder + ListeB.Strings[i]) then
   FileHashTable.Remove(RootFolder + ListeB.Strings[i]);
 end;
Aus dem was in FileHashTable jetzt übrig bleibt, möchte ich die Objekte erzeugen. Nur vielleicht stehe ich gerade auf dem Schlauch. Wie iteriere ich durch FileHashTable ?
  Mit Zitat antworten Zitat
tomkupitz

Registriert seit: 26. Jan 2011
323 Beiträge
 
Delphi 11 Alexandria
 
#17

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 19:27
Du nimmst erstmal alle auf und entfernst dann die aus ListeB. Besser ist Einträge aus ListeB erst gar nicht in ListeA aufzunehmen.

Du durchsuchst ja FileHashTable mit FileHashTable.ContainsKey, soweit ok. Aber ich weiß nicht wie (schnell) ContainsKey sucht.

Geändert von tomkupitz (24. Aug 2023 um 19:29 Uhr)
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#18

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 21:09
Zitat:
Du nimmst erstmal alle auf und entfernst dann die aus ListeB. Besser ist Einträge aus ListeB erst gar nicht in ListeA aufzunehmen.
So war es ja vorher und das war elendig langsam. Bei meinen Testdaten und mit dem alten Code hat das rund 4 Sekunden gedauert. Mit dem neuen Code jetzt nur noch wenn überhaupt 0,1 Sekunden.
Klar hat der neue Code nachteile. So kann ich keine Wildcards mehr verwenden, weil Strings 1zu1 abgeglichen werden. Aber besser der Code ist schnell.

Hier grob erklärt was ich jetzt mache

- Winapi.Windows.FindFirstFileEx() holt mir alle Dateien eines Verzeichnisses und fügt diese in meine Liste HashListe ein
type TFileHashTable = TDictionary<string, TWin32FindData>; var FileHashTable: TFileHashTable;

- ist das getan, gehe ich durch meine Liste B. Alles was in der fixen Liste B ist, wird aus der HashListe entfernt
Delphi-Quellcode:
for i := 0 to ListeB.Count - 1 do
 begin
  if FileHashTable.ContainsKey(RootFolder + ListeB.Strings[i]) then // ich bin mir nicht sicher, ob <Liste>.Remove selber nochmal prüft, ob der String vorhanden ist.
   FileHashTable.Remove(RootFolder + ListeB.Strings[i]);
 end;
- jetzt ist die HashListe bereinigt (alle Pfade aus Liste B sind jetzt nicht mehr dort drin)
- jetzt die Einträge der HashListe in meine eigentliche Liste A überführen, mit der ich weiterarbeite
Delphi-Quellcode:
for Key in FileHashTable.Keys do
 begin
  ...
 end;
Ja, Wildcards wären jetzt schön. Aber ich bin erstmal zufrieden.

Geändert von DieDolly (24. Aug 2023 um 21:16 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#19

AW: Dateiliste gefiltert erstellen

  Alt 24. Aug 2023, 23:40
Hallo DieDolly, ich bin mir nicht sicher ob das hier schneller ist aber so mache ich es.
Delphi-Quellcode:
program Project12;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.Classes,
  System.SysUtils,
  Generics.Collections;

type
  TTrieFilter = class
  private
    FChildren: TObjectDictionary<Char, TTrieFilter>;
    FIsWord: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AddWord(const Word: string);
    function ContainsWord(const Word: string): Boolean;
  end;

constructor TTrieFilter.Create;
begin
  FChildren := TObjectDictionary<Char, TTrieFilter>.Create([doOwnsValues]);
  FIsWord := False;
end;

destructor TTrieFilter.Destroy;
begin
  FChildren.Free;
  inherited;
end;

procedure TTrieFilter.AddWord(const Word: string);
var
  Node: TTrieFilter;
  Ch: Char;
  ChildNode: TTrieFilter;
begin
  Node := Self;
  for Ch in Word do
  begin
    if not Node.FChildren.TryGetValue(Ch, ChildNode) then
    begin
      ChildNode := TTrieFilter.Create;
      Node.FChildren.Add(Ch, ChildNode);
    end;
    Node := ChildNode;
  end;

  if not Node.FIsWord then
    Node.FIsWord := True;
end;

function TTrieFilter.ContainsWord(const Word: string): Boolean;
var
  Node: TTrieFilter;
  Ch: Char;
begin
  Node := Self;
  for Ch in Word do
  begin
    if Node.FChildren.ContainsKey(Ch) then
    begin
      Node := Node.FChildren[Ch];
      if Node.ContainsWord(Copy(Word, 2, Length(Word) - 1)) then
        Exit(True)
      else
        Exit(False);
    end;
  end;

  Result := Node.FIsWord;
end;

var
  SLDaten, SLFilter, SLOutput: TStringList;
  Trie: TTrieFilter;
  I: Integer;
begin
  try
    SLFilter := TStringList.Create;
    SLDaten := TStringList.Create;
    SLOutput := TStringList.Create;
    Trie := TTrieFilter.Create;
    try
      // beispielhaft deine filter liste
      SLFilter.Add('Sub1\Sub2\File1.exe');
      SLFilter.Add('FileX.exe');
      SLFilter.Add('Sub1\FileY.exe');

      // hier die klasse mit den filtern befüllen
      for I := 0 to Pred(SLFilter.Count) do
        Trie.AddWord(SLFilter[I]);

      // das hier überspringen und gleich zum filtern weiter
      // stell dir vor das ist deine dateiliste
      // ps: die reihenfolge ist absolute irrelevant
      SLDaten.Add('c:\Hallo DieDolly\Sub1\Sub2\File1.exe');
      SLDaten.Add('WasAuchImmerFileX.exeHierSteht, es triggert');
      SLDaten.Add('\\\Sub2\FileY.exe'); // das ist das einzige was übrig bleibt


      // Filter den input raus
      for I := 0 to Pred(SLDaten.Count) do
        if not Trie.ContainsWord(SLDaten[I]) then
          SLOutput.Add(SLDaten[I]);

      // darstellen was übrig blieb
      for I := 0 to Pred(SLOutput.Count) do
        WriteLn(SLOutput.Strings[I]);

    finally
      SLDaten.Free;
      SLFilter.Free;
      SLOutput.Free;
      Trie.Free;
    end;
    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Gerne würde ich ein paar brauchbare Benchmark Resultate sehen im Vergleich zu dem THashItem falls Dir meine Klasse gefällt.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:07 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz