Folder søk algoritme

stemmer
0

Ikke sikker på om dette er den vanlige typen spørsmål som blir spurt rundt her, eller om jeg skal få noen svar på dette, men jeg leter etter en pseudo-kode tilnærming til å generere DB linking poster fra en mappestruktur som inneholder bilde filer.

Jeg har et sett med mapper, strukturert som folllows:

+-make_1/
  | +--model_1/
  |    +-default_version/
  |    |   +--1999
  |    |   +--2000
  |    |   |   +--image_01.jpg
  |    |   |   +--image_02.jpg
  |    |   |   +--image_03.jpg
  |    |   |   ...
  |    |   +--2001
  |    |   +--2002
  |    |   +--2003
  |    |   ...
  |    |   +--2009
  |    +--version_1/
  |    |   +--1999
  |    |   ...
  |    |   +--2009
  |    +--version_2/
  |    |   +--1999
  |    |   +--2000
  |    |   +--2001
  |    |   |   +--image_04.jpg
  |    |   |   +--image_05.jpg
  |    |   |   +--image_06.jpg
  |    |   |   ...
  |    |   +--2002
  |    |   +--2003
  |    |   |   +--image_07.jpg
  |    |   |   +--image_08.jpg
  |    |   |   +--image_09.jpg
  |    |   ...
  |    |   +--2009
  ...  ... ...  

I hovedsak representerer det mulige bilder for kjøretøyer, etter år med start i 1999.

Merker og modeller (f.eks Merke: Alfa Romeo, Modell: 145) kommer i ulike trimme eller versjoner. Hver trim, eller versjonen kan finnes i en rekke kjøretøyer som vil se det samme, men har si forskjeller i drivstofftype eller motorkapasitet.

For å lagre duplisering, mappestrukturen gjør ovenfor bruk av en standardmappe ... Og bildene vises for standardversjonen fra 2000 og utover. Jeg trenger å produsere lenker tabell for hver versjon - basert på om har sine egne overordnede bilder, eller om gjøre bruk av standardversjonen ...

Så for eksempel, har VERSION_1 ingen bildefiler, så jeg trenger å gjøre koblinger for å standard bilder, som starter i 2000 og fortsatte frem til 2009.

Versjon 2 derimot starter med standard bildene i 2000, men bruker da to nye sett først for 2001-2002, og deretter 2003-2009. Listen over lenker som kreves er derfor ...

version    start     end   file_name
=======    =====   =====   =========
version_1   2000    2009   image_01.jpg
version_1   2000    2009   image_02.jpg
version_1   2000    2009   image_03.jpg
...
version_2   2000    2001   image_01.jpg
version_2   2000    2001   image_02.jpg
version_2   2000    2001   image_03.jpg
version_2   2001    2003   image_04.jpg
version_2   2001    2003   image_05.jpg
version_2   2001    2003   image_06.jpg
version_2   2003    2009   image_07.jpg
version_2   2003    2009   image_08.jpg
version_2   2003    2009   image_09.jpg
...

(Standard er nettopp det - et sted holder, og ingen linker er nødvendig for det.)

I øyeblikket er jeg kjører gjennom mappene, bygge matriser, og deretter trimming fettet på slutten. Jeg bare lurte på om det var en snarvei, ved hjelp av noen form for tekst-behandling tilnærming? Det er ca 45 000 mapper, hvorav de fleste er tom :-)

Publisert på 05/07/2009 klokken 20:43
kilden bruker
På andre språk...                            


1 svar

stemmer
1

Her er noen Python pseudokode, ganske nær kjørbar (trenger egnede import og en def for en writerow funksjon som vil gjøre selve skrivingen - det være seg til en mellomliggende fil, DB, CSV, uansett):

# first, collect all the data in a dict of dicts of lists
# first key is version, second key is year (only for non-empty years)

tree = dict()
for root, dirs, files in os.walk('make_1/model_1'):
    head, tail = os.path.split(root)
    if dirs:
       # here, tail is a version
       tree[tail] = dict
    elif files:
       # here, tail is a year
       tree[os.path.basename(head)][tail] = files

# now specialcase default_version
default_version = tree.pop('default_version')
# determine range of years; rule is quite asymmetrical:
#   for min, only years with files in them count
min_year = min(d for d in default_version if default_version[d])
#   for max, all years count, even if empty
max_year = max(default_version)

for version, years in tree.iteritems():
    current_files = default_version[min_year]
    years.append(max_year + 1)
    y = min_year
    while years:
        next_change = min(years)
        if y < next_change:
            for f in current_files:
                writerow(version, y, next_change-1, f)
        y = next_change
        current_files = years.pop(y)

En tvetydighet i spec og eksempel er om det er mulig for default_version å endre settet med filer i noen år - her, jeg antar at det ikke skjer (kun spesielle versjoner endre på den måten, standardversjonen bærer alltid ett sett filer).

Hvis dette ikke er tilfelle, hva skjer hvis standardversjonen endringer i år (si) 1999 og 2003, og version1 endringer i 2001 og 2005 - hvilke filer bør versjon en bruk for 03 og 04, de nye i standardversjonen eller de som det er angitt i 01?

I den mest komplisert versjon av spesifikasjonen (der både default_version og en bestemt en kan endre, med den siste endringen tar forrang, og hvis både spesifikk og standard endring i samme år da bestemt å ta forrang) man trenger for å få alle "neste endring år" sekvens, for hver bestemt versjon, med forsiktig "prioritet sammenslåing" av sekvensene av endrings år for mislighold og bestemt versjon, i stedet for bare å bruke years(sekvensen av endringer i den spesifikke versjonen) som jeg gjør her - og hver endring år plassert i sekvensen må være knyttet til de relevante filer av kurset.

Så hvis det nøyaktige spesifikasjonen kan du komme til uttrykk, nede ved corner tilfeller, kan jeg vise hvordan du gjør det nødvendig å slå sammen ved å endre denne pseudo - Jeg vil heller ikke gjøre jobben til de nøyaktige spesifikasjoner er avklart, fordi hvis spesifikasjoner er faktisk enklere, vil arbeidet være unødvendige -)

Edit : som en ny kommentar avklart, er de nøyaktige spesifikasjoner faktisk den mest komplekse en, så vi har ikke gjøre sammenslåing riktig. Så løkken på slutten av den forenklede svaret ovenfor endringer:

for version, years_dict in tree.iteritems():
    # have years_dict override default_version when coincident
    merged = dict(default_version, **years_dict)
    current_files = merged.pop(min_year)
    merged[max_year + 1] = None
    y = min_year
    while merged:
        next_change = min(merged)
        for f in current_files:
            writerow(version, y, next_change-1, f)
        y = next_change
        current_files = merged.pop(y)

Nøkkelen endringen er merged = dict(...linje: i Python, betyr dette å gjøre sammen en ny dict (en dict er en generisk kartlegging, ville vanligvis kalles en HashMap på andre språk) som er summen, eller flette, av default_versionog years_dict, men når en nøkkelen er til stede i begge disse, verdien fra years_dictforrang - som møter viktig forutsetning for et år som er til stede (dvs. er et år med en endring i filer) i begge.

Etter at det er vanlig seiling: anydict.pop (somekey) returnerer den verdi som svarer til den tast (og også fjerner den fra anydict); min (anydict) returnerer den minste nøkkelen i ordboken. Legg merke til "sentinel" idiom på merged[max_year + 1] = None: dette sier at året "den ene etter den max en" er alltid anses å være en endring år (med en dummy plassholder verdien av Ingen), slik at det siste settet med rader er alltid skrevet riktig (med en maksimal år max_year + 1 - 1, dvs. nøyaktig max_yearetter ønske).

Denne algoritmen er ikke maksimalt effektiv, bare enkleste! Vi gjør min(merged)om og om igjen, noe som gjør det O (N squared) - Jeg tror vi har råd til det fordi hver mergedbør ha et par dusin endrings år på de fleste, men en purist ville krympe. Vi kan selvsagt presentere en O (N Løgn) løsning - bare sortere de årene en gang for alle og gå som sekvens for å få de påfølgende verdier for next_change. Bare for fullstendighet ...:

default_version[max_year + 1] = None

for version, years_dict in tree.iteritems():
    merged = dict(default_version, **years_dict)
    for next_change in sorted(merged):
        if next_change > min_year:
            for f in merged[y]:
                writerow(version, y, next_change-1, f)
        y = next_change

Her sortedgir en liste med nøklene mergedi sortert rekkefølge, og jeg har byttet til foruttalelsen til å gå den listen fra begynnelse til slutt (og en hvis uttalelser til utgang ingenting første gang gjennom). Den Sentinel settes nå i default_version (slik at det er utenfor sløyfen, for en annen svak optimalisering). Det er morsomt å se at dette optimalisert versjon (i hovedsak fordi det fungerer på et litt høyere nivå av abstraksjon) viser seg å være mindre og enklere enn de forrige ;-).

Svarte 05/07/2009 kl. 21:57
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more