Algoritmul de cautare Folder

voturi
0

Nu sunt sigur dacă acesta este genul obișnuit de întrebare care devine întrebat pe aici, sau dacă voi primi nici un răspuns la asta, dar caut o abordare pseudo-cod pentru generarea de DB înregistrări care leagă dintr-o imagine de structură dosar care conține fișiere.

Am un set de dosare, structurate ca 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
  ...  ... ...  

În esență, aceasta reprezintă posibile imagini pentru vehicule, pe an, începând din 1999.

Mărci și modele (de exemplu, Marca: Alfa Romeo, Model: 145) vin în diverse ornamente sau versiuni. Fiecare trim, sau versiune poate fi găsită într-un număr de vehicule, care va arata la fel, dar au spus diferențele de tipul de combustibil sau capacitatea motorului.

Pentru a salva duplicarea, structura de directoare de mai sus face uz de un dosar implicit ... Și imaginile apar pentru versiunea implicită începând din 2000. Am nevoie pentru a produce tabelul de link-uri pentru fiecare versiune - pe baza faptului dacă au propriile lor imagini determinante, sau dacă face uz de versiunea implicită ...

Deci, de exemplu, VERSION_1 nu are fișiere de imagine, așa că am nevoie pentru a face link-uri pentru a imaginilor implicite, începând cu anul 2000 și continuând până în 2009.

Versiunea 2 pe de altă parte, începe folosind imaginile implicite în 2000, dar apoi folosește două seturi noi în primul rând pentru 2001-2002, apoi 2003-2009. Lista de link-uri necesare sunt, prin urmare, ...

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
...

(Implicit este doar că - un loc de titular, și nu link-uri sunt necesare pentru aceasta.)

În momentul de față Alerg prin foldere, construirea de matrice, și apoi tunderea grăsimea la sfârșitul anului. Mă întrebam dacă a existat o tăietură scurtă, folosind un fel de abordare de procesare de text? Există aproximativ 45.000 dosare, dintre care cele mai multe sunt goale :-)

Întrebat 05/07/2009 la 21:43
sursa de către utilizator
În alte limbi...                            


1 răspunsuri

voturi
1

Iată câteva pseudocod Python, destul de aproape de executabil (are nevoie de importuri adecvate și o definiție pentru o funcție writerow care va face scrierea efectivă - fie că este vorba într-un fișier intermediar, DB, CSV, oricare ar fi):

# 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)

O ambiguitate în spec și exemplu este dacă este posibil pentru default_version pentru a modifica setul de fișiere în câțiva ani - aici, eu sunt presupunând că nu se întâmplă (numai anumite versiuni schimba în acest fel, versiunea implicită poartă întotdeauna un set de fișiere).

În cazul în care acest lucru nu este cazul, ceea ce se întâmplă în cazul în care versiunea implicită modificări ani (să zicem), 1999 și 2003, precum și modificările version1 în 2001 și 2005 - ce fișiere ar trebui să versiunea 1 pentru utilizare 03 și 04, noile cele din versiunea implicită sau cele pe care le sunt specificate în 01?

În versiunea cea mai complicată a spec ( în cazul în care atât default_version și unul specific se poate schimba, cu cea mai recenta schimbare au prioritate, iar în cazul în care atât schimbarea specifică și implicit în același an , atunci prevalând specifice) este nevoie pentru a obține toate „anul viitor schimbare“ secvență, pentru fiecare versiune specifică, cu atenție „contopire prioritate“ a secvențelor de ani de schimbare pentru implicit și versiunea specifică, în loc să utilizați numai years(secvența de modificări în versiunea specifică) , așa cum fac eu aici - și în fiecare an de schimbare plasate în secvența trebuie să fie asociată cu setul corespunzător de fișiere desigur.

Deci, dacă spec exactă poate vă rugăm să fi exprimate, până la cazurile de colț, pot arăta cum se face contopirea necesare prin modificarea acestei pseudocod - prefer să nu fac lucrarea până când specificațiile exacte sunt clarificate, pentru că, în cazul în care specs sunt într-adevăr mai simple, lucrarea ar fi care nu sunt necesare -!)

Edit : ca un nou comentariu clarificat, specificațiile exacte este într - adevăr cea mai complexă, așa că avem de a face face Fuzionarea în mod corespunzător. Deci bucla de la sfârșitul răspunsului simplist de mai sus modificări:

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)

Schimbarea cheie este merged = dict(...linia: în Python, acest lucru înseamnă a face fuzionat un nou dict (un dict este o mapare generică, ar fi numit de obicei o HashMap în alte limbi) , care este suma, sau fuziona, de default_versionși years_dict, dar atunci când o cheie este prezentă în ambele, valoarea de la years_dictare prioritate - care îndeplinește condiția cheie pentru un an , care este prezent ( de exemplu, este un an cu o schimbare în fișiere) în ambele.

După aceea este neteda navigatie: anydict.pop (somekey) returnează valoarea corespunzătoare cheii (și , de asemenea , elimină din anydict); min (anydict) returnează cheia minimă în dicționar. Notă „santinelă“ idiom la merged[max_year + 1] = None: aceasta spune că anul „unul după cel maxim“ este considerat întotdeauna a fi o schimbare de ani (cu o valoare substituent fictiv Niciunul), astfel încât ultimul set de rânduri este întotdeauna scris corect (cu un an de maxim max_year + 1 - 1, adică exact max_year, după cum se dorește).

Acest algoritm nu este eficient la maximum, chiar mai simplu! Facem min(merged)peste si peste, făcându - l O (N la pătrat) - Cred că ne putem permite asta pentru că fiecare mergedar trebui să aibă o duzină de puține schimbări ani cel mult, dar puriste ar crispeze. Desigur , putem prezenta o soluție (N LOGN) O - trebuie doar să sorteze ani o dată pentru totdeauna și merge pe acea secvență pentru a obține valorile succesive pentru next_change. Doar pentru completare ...:

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

Aici sortedoferă o listă cu cheile mergedîn ordine sortată și am trecut la fordeclarația de a merge pe acea lista de la început până la sfârșit (și un dacă declarații de ieșire nimic prima dată prin intermediul). Santinela este acum pus în default_version (deci este în afara buclei, pentru o altă optimizare ușoară). Este amuzant pentru a vedea că această versiune optimizată ( în esență , pentru că funcționează la un nivel ușor mai ridicat de abstractizare) se dovedește a fi mai mici și mai simple decât cele anterioare ;-).

Publicat 05/07/2009 la 22:57
sursa de către utilizator

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