"Dubletten" finden

Nutzung, Komponenten, .NET

Moderator: Moderatoren

Antworten
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

"Dubletten" finden

Beitrag von AUGE_OHR »

hi,

ich habe eine grosse DBF mit MP3 Info welche ich mittels
M$ Mediaplayer OCX erstellt habe.

Nun will ich "Dubbletten" finden. sortiert und suchen tue ich nach :

UPPER(Artist)+UPPER(Title)+DTOS(MP3Date)

z.Z. arbeitet meinem code mit SKIP 1 sowie SKIP-1
um herraus zu finden ob der nächste Datensatz eine
"Dubblette" ist.

Code: Alles auswählen

DO WHILE !EOF()
...
   cLast := UPPER(Artist)+UPPER(Title)
...
   SKIP
   IF UPPER(Artist)+UPPER(Title) == cLast
      markit()
      SKIP -1
      markit()
      SKIP
   ELSE
...
   ENDIF
ENDDO
gibt es eine bessere "Technik" um "Dubbletten zu finden ?

gruss by OHR
Jimmy
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15689
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Wenn die Sortierung stimmt ist das bestimmt gut.

Aber warum markierst du beide, ich würde bei jedem Satz den Suchbegriff in eine cVar packen und den nächsten dann mit dieser vergleichen.
Sind beide gleich lösche ich den aktuellen Satz und vergleiche den nächsten. Alle gleichen Sätze werden zur Löschung markiert, beim nächsten ungleichen Satz wird die cVar auf diesen gesetzt. Zum Schluß ein pack.

Ob allerdings die Kriterien reichen um eine MP3 auf Gleichheit zu prüfen, kann ich nicht beurteilen.

Eventuell solltest du beim Vergleich eine Funktion verwenden, welche darin alle Blanks, und folgende Zeichen entfernt: .,;-_'+()
Schließlich kann man die Lieder verschieden schreiben ...
Gruß
Hubert
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15689
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hallo,

da fällt mir gerade noch ein ...

Set index on UPPER(Artist)+UPPER(Title)+DTOS(MP3Date) to xxx UNIQUE

danach ist immer nur der erste Datensatz erhalten. Nun ein copy to und man hat eine sortierte Datei mit einmaligem Inhalt. Dies dürfte der schnellste Weg sein.
Gruß
Hubert
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

brandelh hat geschrieben: Wenn die Sortierung stimmt ist das bestimmt gut.

Aber warum markierst du beide, ich würde bei jedem Satz den Suchbegriff in eine cVar packen und den nächsten dann mit dieser vergleichen. Sind beide gleich lösche ich den aktuellen Satz und vergleiche den nächsten.
tja und wenn Record 1-3 "dubbletten" sind, wie fange ich mit cVar an ?
da ich nach Datum sortiert habe, möchte ich den "lates" behalten
Alle gleichen Sätze werden zur Löschung markiert, beim nächsten ungleichen Satz wird die cVar auf diesen gesetzt.
angenommen 6-9 sind wieder "dubbletten". also irgendwann komme
ich auf die 6, cVar := NeueDaten
nun bin ich auf der 7 und merke "dubblette", also markieren. Aber
die 6 gehört ja auch dazu, also wieder zurück ...oder ?

wenn ich auf der 6 bin kann ich ja noch nicht "ahnen" das die 7
eine "dubblette" ist. ("ahnen" = OrdKeyCount() ... PDR 5206 )
Ob allerdings die Kriterien reichen um eine MP3 auf Gleichheit zu prüfen, kann ich nicht beurteilen.
das ist nur im Beispiel stark abgekürzt. z.Z. nehme ich die Filesize
und Duration noch zum (eindeutigen) identifizieren.
Schließlich kann man die Lieder verschieden schreiben ...
[/quote]

deshalb nehme ich die M$ Mediaplayer Info (file laden, anspielen,
Info = ID3 Tag v1.1 auslesen, nächstes file ...) welche "im file"
vorhanden sind. gegen "Schreibfehler" hab ich aus noch kein
Rezept gefunden. Die muss der User eben noch per Browser
"manuell" erledigen.

gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

brandelh hat geschrieben:Hallo,

da fällt mir gerade noch ein ...

Set index on UPPER(Artist)+UPPER(Title)+DTOS(MP3Date) to xxx UNIQUE

danach ist immer nur der erste Datensatz erhalten. Nun ein copy to und man hat eine sortierte Datei mit einmaligem Inhalt. Dies dürfte der schnellste Weg sein.
yup ... aber ich hatte vergessen zu erwähnen das ich die "dubbletten"
auch physikalisch löschen möchte und der komplette Path+file auch
in der DBF steht ...

danke, gruss by OHR
Jimmy
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Jimmy,
AUGE_OHR hat geschrieben:tja und wenn Record 1-3 "dubbletten" sind, wie fange ich mit cVar an ?
da ich nach Datum sortiert habe, möchte ich den "lates" behalten
dann nimm das Datum doch einfach mit in den Index - und zwar absteigend!
Dadurch steht immer der jüngste zuerst.
Nun gehst Du (wie Hubert vorgeschlagen hat) durch Deine Datei durch und löscht von doppelten immer die Datei und den Eintrag - den ersten lässt Du immer drin stehen.
Quasi-Pseudo-Code:

Code: Alles auswählen

cDummy := ""
index on UPPER( Artist ) + UPPER( Title ) + DESCEND( DTOS( MP3Date ) ) to xxx
go top
do while .not. eof()
  if cDummy <> UPPER( Artist ) + UPPER( Title )
    cDummy := UPPER( Artist ) + UPPER( Title )
  else
    delete file( pfad + dateiname )
    delete
  endif
  skip
enddo
pack
Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

hi,
Martin Altmann hat geschrieben: Nun gehst Du (wie Hubert vorgeschlagen hat) durch Deine Datei durch und löscht von doppelten immer die Datei und den Eintrag - den ersten lässt Du immer drin stehen.
Quasi-Pseudo-Code:

Code: Alles auswählen

cDummy := ""
index on UPPER( Artist ) + UPPER( Title ) + DESCEND( DTOS( MP3Date ) ) to xxx
go top
do while .not. eof()
  if cDummy <> UPPER( Artist ) + UPPER( Title )
    cDummy := UPPER( Artist ) + UPPER( Title )
  else
    delete file( pfad + dateiname )
    delete
  endif
  skip
enddo
pack
Ja, das mit UNIQUE ist das Endergebniss was ich "wünsche" ...

Ich möchte dem User alle "dubbletten" zeigen/markieren,
wobei ich dann "vorschlage" die "lates" zu behalten.

mein jetziger code funktioniert zwar (Zeit spielt keine
Rolle), aber er sieht einfach "nicht gut aus" ... :)

nun hab ich den Vorschlag erhalten mit 2x Index zu
arbeiten, einmal "normal" und einmal "Unique". Wenn
man unter verwendung von 2x ALIAS die nun "Syncronisiert"

SELECT 1
USE MP3 ALIAS ALLMP3 ; Index "normal"
SELECT 2
USE MP3 ALIAS SMALL ; Index "Unique"

SELECT ALLMP3
DO WHILE WhatToDo() ??


gruss by OHR
Jimmy
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15689
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hallo Jimmy,

und wo soll da der Vorteil liegen ?
Nimm die gewünschte Sortierfolge und die Technik wie beschrieben und es reicht ein Index ... nur mußt du bei fehlender Löschung halt doch die Markierung setzen ...

Code: Alles auswählen

index wie gewünscht...
cVar = "#"
nErsteRecNo := 0  // erster Satz mit cVar Suchbegriff

do while ! eof()
     if cVar = aktueller Suchbegriff
        // dubletten !
        go nErsteRecNo
        do while ! eof() .and. cVar = aktueller Suchbegriff
             setze Markierung
             skip
        enddo
     else
        cVar := aktueller Suchbegriff        
        nErsteRecNo := recno()
     endif 
     skip
enddo
Ein Durchlauf in gewünschter Sortierung (erster oder letzter Satz am Anfang - spielt keine Rolle) und alle Einträge sind markiert ... mach mit denen was du willst.

Statt der do while Schleifen könnte man die schnelleren DBEVAL oder Replace Befehle jeweils mit codeblock für Aktion, FOR, WHILE und natürlich REST = .t. einsetzen. Aber das hier ist übersichtlicher.
Gruß
Hubert
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

hi,
brandelh hat geschrieben:

Code: Alles auswählen

index wie gewünscht...
cVar = "#"
nErsteRecNo := 0  // erster Satz mit cVar Suchbegriff

do while ! eof()
     if cVar = aktueller Suchbegriff
        // dubletten !
        go nErsteRecNo
        do while ! eof() .and. cVar = aktueller Suchbegriff
             setze Markierung
             skip
        enddo
     else
        cVar := aktueller Suchbegriff        
        nErsteRecNo := recno()
     endif 
     skip
enddo
DAS sieht doch schon sehr gut aus. kurz, übersichtlich einfach "schön" !

ich habe auch weiter gedacht mit den letzten Vorschlägen. Dabei bin
ich irgendwie bei RECNO() hängen geblieben :

Code: Alles auswählen

PROCEDURE MAIN
LOCAL cSuch := ""
LOCAL aMark := {}

   USE MP3 ALIAS SUCHDUPP

   // INDEX ON UPPER(ARTIST+TITEL+DTOS(W9DATE)) TO ArtistTitel
   SET INDEX TO ArtistTitel

   GO TOP
   DO WHILE !EOF()
      IF EMPTY(SUCHDUPP->ARTIST) .OR. EMPTY(SUCHDUPP->TITEL)
         SKIP
         LOOP
      ENDIF

      AADD(aMark, {RECNO()} )
      IF SUCHDUPP->ARTIST+SUCHDUPP->TITEL == cSuch
         SKIP
      ELSE
         cSuch := SUCHDUPP->ARTIST+SUCHDUPP->TITEL
         SKIP

         IF SUCHDUPP->ARTIST+SUCHDUPP->TITEL == cSuch
         ELSE
            ADEL(aMark,LEN(aMark))
            ASize( aMark, LEN(aMark)-1 )
         ENDIF
      ENDIF
   ENDDO

   GO TOP
   COPY TO DUPPFILE FOR NUMBERCOPY(aMark)
   CLOSE

RETURN

FUNCTION NUMBERCOPY(aMark)
LOCAL RETVAR := .F.
LOCAL nRec      := RECNO()
LOCAL nPosi

   nPosi :=  ASCAN(aMark,{|aVal| aVal[1] == nRec })
   IF nPosi > 0
      RETVAR := .T.
   ENDIF

RETURN (RETVAR)
das erspart das "rückwärtz" springen und ein REPLACE für die
markierung spare ich mir auch.

danke nochmal für die Ideen und Vorschläge

gruss by OHR
Jimmy
Antworten