Folder zoekalgoritme

stemmen
0

Niet zeker of dit is de gebruikelijke soort vraag die hier in de buurt wordt gevraagd, of als ik geen antwoorden op deze ene krijgt, maar ik ben op zoek naar een pseudo-code aanpak voor het genereren van DB koppelen records van mapstructuur met beeld bestanden.

Ik heb een set van mappen, gestructureerd als 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
  ...  ... ...  

In wezen, het vertegenwoordigt mogelijke beelden voor voertuigen, per jaar vanaf 1999.

Maakt en modellen (bijv Merk: Alfa Romeo, Model: 145) zijn er in verschillende hoezen of versies. Elke trim, of versie kan worden gevonden in een aantal voertuigen die hetzelfde zal uitzien, maar moet zeggen dat de verschillen in type brandstof of cilinderinhoud.

Om dubbel werk te besparen, de mappenstructuur hierboven maakt gebruik van een standaard map ... En afbeeldingen worden weergegeven voor de standaard versie vanaf 2000. Ik moet de links tafel te produceren voor elke versie - op basis van de vraag of het hebben hun eigen dwingende beelden, of gebruik maken van de standaard versie ...

Dus bijvoorbeeld, VERSION_1 heeft geen beeldbestanden, dus ik moet links voor om de standaard afbeeldingen, te beginnen in 2000 en voortgezet tot 2009 te maken.

Versie 2 aan de andere kant begint met behulp van de standaard afbeeldingen in 2000, maar dan maakt gebruik van twee nieuwe sets eerst voor 2001-2002, en dan 2003-2009. De lijst met links die nodig zijn dus ...

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

(Standaard is alleen dat - een plaats houder, en geen links nodig zijn voor het.)

Op het moment dat ik ben actief door de mappen, het opbouwen van arrays, en dan trimmen het vet aan het eind. Ik vroeg me af of er een kortere weg, met behulp van een soort van tekst-processing aanpak? Er zijn ongeveer 45.000 folders, waarvan de meeste zijn leeg :-)

De vraag is gesteld op 05/07/2009 om 21:43
bron van user
In andere talen...                            


1 antwoorden

stemmen
1

Hier is wat Python pseudocode, vrij dicht bij uitvoerbare (moet geschikt invoer en een def voor een writerow functie die het eigenlijke schrijven zal doen - of het nu om een ​​intermediair bestand, DB, CSV, wat dan ook):

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

Een dubbelzinnigheid in de spec en voorbeeld is de vraag of het mogelijk is voor de default_version om de set van bestanden in een paar jaar te veranderen - hier, veronderstel ik dat niet gebeurt (alleen specifieke versies te veranderen op die manier, de standaardversie draagt ​​altijd een set van bestanden).

Als dit niet het geval is, wat gebeurt er als de standaardversie veranderingen in jaren (bijvoorbeeld) 1999 en 2003, en version1 veranderingen in 2001 en 2005 - welke bestanden moeten versie 1 te gebruiken voor 03 en 04, de nieuwe in de standaardversie , of die gepreciseerd in 01?

In de meest gecompliceerde versie van de spec (waar zowel default_version en een specifieke kan veranderen, met de meest recente wijziging die voorrang heeft, en als zowel specifieke en standaard verandering in hetzelfde jaar dan is de specifieke hebben voorrang) moet men alle te krijgen "volgende verandering jaar" sequentie, voor elke specifieke versie, door een zorgvuldige "prioritaire samenvoeging" van de sequenties van de verandering jaar voor verzuim en specifieke versie, in plaats van alleen met behulp van years(de volgorde van de veranderingen in de specifieke versie) zoals ik hier doe - en elke verandering jaar geplaatst in de volgorde moet worden gekoppeld aan de juiste set bestanden natuurlijk.

Dus als de exacte spec kan alstublieft worden uitgedrukt, aan de cornervlag gevallen, ik kan laten zien hoe dat te doen de benodigde samenvoegen door het wijzigen van deze pseudo-code - ik liever niet het werk doen totdat de exacte specificaties worden verduidelijkt, want als de specs zijn inderdaad eenvoudiger, zou het werk onnodige zijn -!)

Bewerken : als een nieuwe reactie verduidelijkt, de exacte specificaties is inderdaad de meest complexe een, dus we doen het samen te voegen op de juiste wijze. Dus de lus aan het eind van de simplistische antwoord op bovenstaande wijzigingen in:

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)

De belangrijkste verandering is de merged = dict(...regel: in Python, dit betekent voor maken samengevoegd een nieuwe dict (een DICT is een generieke mapping, zouden in het algemeen worden genoemd een HashMap in andere talen) die de som, of samenvoegen van default_versionen years_dict, maar wanneer een key aanwezig in beide daarvan is, de waarde van years_dictvoorrang - waarin de belangrijkste voorwaarde voldoet voor een jaar die aanwezig is (dat wil zeggen, is het hele jaar met een verandering in de bestanden) in beide.

Daarna is het een leien dakje: anydict.pop (somekey) geeft de waarde die overeenkomt met de sleutel (en ook verwijderd uit anydict); min (anydict) geeft de minimale sleutel in het woordenboek. Let op de "schildwacht" idioom op merged[max_year + 1] = None: dit zegt dat het jaar "een na de max one" wordt altijd beschouwd als een overgang jaar (met een dummy placeholder waarde Geen), zodat de laatste set rijen altijd goed is geschreven (maximaal jaar max_year + 1 - 1, dat is precies max_yearzoals gewenst).

Dit algoritme is niet maximaal efficiënt, net eenvoudigste! We doen min(merged)steeds weer, waardoor het O (N kwadraat) - Ik denk dat we ons kunnen veroorloven dat, omdat elk mergedeen paar dozijn change-jaar hooguit zou moeten hebben, maar een purist zou huiveren. We kunnen natuurlijk presenteren een O (N LOGN) -oplossing - net gekozen de jaren eens en voor altijd en loop die volgorde om de opeenvolgende waarden te krijgen voor next_change. Gewoon voor de volledigheid ...:

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

Hier sortedstaat een lijst met de sleutels van mergedin gesorteerde volgorde, en ik ben overgestapt naar de forverklaring die lijst lopen van begin tot eind (en een if-statements voor het uitvoeren van niets de eerste keer door). De schildwacht is nu gezet in default_version (dus het is buiten de lus, voor een andere lichte optimization). Het is grappig om te zien dat deze geoptimaliseerde versie (voornamelijk omdat het werkt op een iets hoger niveau van abstractie) blijkt te zijn kleiner en eenvoudiger dan de vorige ;-) zijn.

antwoordde op 05/07/2009 om 22:57
bron van user

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