αλγόριθμος αναζήτησης φακέλου

ψήφοι
0

Δεν είμαι σίγουρος αν αυτό είναι το συνηθισμένο είδος της ερώτησης που παίρνει ζήτησε εδώ γύρω, ή αν θα πάρω καμία απάντηση σε αυτό, αλλά ψάχνω για μια προσέγγιση ψευδο-κώδικα για τη δημιουργία DB σύνδεση εγγραφών από μια δομή φακέλου που περιέχει την εικόνα αρχεία.

Έχω μια σειρά από φακέλους, διαρθρώνεται ως 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
  ...  ... ...  

Στην ουσία, αποτελεί δυνατό εικόνες για τα οχήματα, από το έτος αρχής γενομένης από το 1999.

Κάνει και μοντέλα (π.χ. Μοντέλο: Alfa Romeo, Μοντέλο: 145) έρχονται σε διάφορα διακοσμητικά ή εκδόσεις. Κάθε τελειώματα, ή έκδοση μπορεί να βρεθεί σε μια σειρά από οχήματα τα οποία θα δούμε το ίδιο, αλλά έχουν πει διαφορές στον τύπο καυσίμου ή τον κυβισμό του κινητήρα.

Για να αποθηκεύσετε επικάλυψη, η δομή του φακέλου παραπάνω κάνει χρήση ενός προεπιλεγμένο φάκελο ... Και εικόνες εμφανίζονται για την προεπιλεγμένη έκδοση από το 2000 και μετά. Θα πρέπει να παράγουν το τραπέζι συνδέσεις για κάθε έκδοση - ανάλογα με το αν το έχουν το δικό τους επιτακτικούς εικόνες, ή αν κάνουν χρήση της προεπιλεγμένης έκδοσης ...

Έτσι, για παράδειγμα, έχει VERSION_1 δεν τα αρχεία εικόνας, γι 'αυτό πρέπει να links για να τις προεπιλεγμένες εικόνες, αρχής γενομένης από το 2000 και συνεχίστηκε μέχρι το 2009.

Έκδοση 2, από την άλλη πλευρά ξεκινά χρησιμοποιώντας τις προεπιλεγμένες εικόνες, το 2000, αλλά στη συνέχεια χρησιμοποιεί δύο νέες σειρές πρώτη για το 2001-2002, και στη συνέχεια 2003-2009. Ο κατάλογος των συνδέσμων που απαιτούνται είναι, ως εκ τούτου ...

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

(Η προεπιλογή είναι ακριβώς αυτό - ο κάτοχος μέρος, και δεν συνδέσεις που απαιτούνται για αυτό.)

Αυτή τη στιγμή είμαι τρέχει μέσα από τους φακέλους, με βάση πίνακες, και στη συνέχεια κόψιμο του λίπους στο τέλος. Απλώς αναρωτιόμουν αν υπήρχε μια μικρή περικοπή, χρησιμοποιώντας κάποιο είδος της προσέγγισης επεξεργασίας κειμένου; Υπάρχουν περίπου 45.000 φάκελοι, οι περισσότεροι εκ των οποίων είναι άδειο :-)

Δημοσιεύθηκε 05/07/2009 στις 21:43
πηγή χρήστη
Σε άλλες γλώσσες...                            


1 απαντήσεις

ψήφοι
1

Εδώ είναι μερικές Python ψευδοκώδικα, πολύ κοντά στο εκτελέσιμο αρχείο (χρειάζεται κατάλληλη εισαγωγές και ευκρίνειας για μια λειτουργία writerow που θα κάνει το πραγματικό γράψιμο - είτε πρόκειται για ένα ενδιάμεσο αρχείο, DB, CSV, οτιδήποτε):

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

Μία ασάφεια στο spec και το παράδειγμα είναι αν είναι δυνατό για την default_version να αλλάξει το σύνολο των αρχείων σε μερικά χρόνια - εδώ, υποθέτω ότι δεν θα συμβεί (μόνο συγκεκριμένες εκδόσεις αλλάξουμε αυτόν τον τρόπο, η προεπιλεγμένη έκδοση φέρνει πάντα ένα σετ των αρχείων).

Εάν αυτό δεν συμβαίνει, τι θα συμβεί αν οι προεπιλεγμένη έκδοση αλλαγές στη χρόνια (ας πούμε) του 1999 και του 2003, και οι αλλαγές Έκδοσης 1 το 2001 και το 2005 - τι αρχεία θα πρέπει έκδοση 1 χρήση για 03 και 04, τα νέα στην προεπιλεγμένη έκδοση , ή εκείνα που καθορίζονται στο 01;

Στην πιο περίπλοκη εκδοχή του spec (όπου και default_version και ένα ειδικό που μπορεί να αλλάξει, με την πιο πρόσφατη αλλαγή να προηγείται, και αν τα δύο συγκεκριμένες και προκαθορισμένες αλλαγή κατά το ίδιο έτος, τότε η συγκεκριμένη λήψη προτεραιότητα) κάποιος πρέπει να πάρει όλα τα «επόμενη αλλαγή χρονιά» σειρά, για κάθε συγκεκριμένη έκδοση, με προσεκτική «συγχώνευση προτεραιότητα» των ακολουθιών των ετών αλλαγής για την προεπιλογή και την συγκεκριμένη έκδοση, αντί απλώς με τη χρήση years(την ακολουθία των αλλαγών στην ειδική έκδοση), όπως κάνω εδώ - και κάθε χρόνο αλλαγή τοποθετούνται με τη σειρά που πρέπει να συνδέεται με το κατάλληλο σύνολο αρχείων του μαθήματος.

Έτσι, αν μπορείτε παρακαλώ να εκφραστεί η ακριβής spec, μέχρι τη γωνία περιπτώσεις, μπορώ να δείξω πώς να κάνετε την απαραίτητη συγχώνευση με την τροποποίηση αυτή ψευδοκώδικα - Θα προτιμούσα να μην κάνει τη δουλειά μέχρι να διευκρινιστούν οι ακριβείς προδιαγραφές, διότι, εάν η specs είναι πράγματι πιο απλό, το έργο θα είναι περιττά! -)

Επεξεργασία : ως ένα νέο σχόλιο διευκρινιστούν οι ακριβείς προδιαγραφές είναι πράγματι η πιο περίπλοκη, έτσι έχουμε κάνει πράξει η συγχώνευση κατάλληλα. Έτσι το βρόχο στο τέλος του απλοϊκή απάντηση παραπάνω αλλαγές:

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)

Η βασική αλλαγή είναι η merged = dict(...γραμμή: σε Python, αυτό σημαίνει να κάνουν συγχωνεύονται ένα νέο dict (α dict είναι μια γενική χαρτογράφηση, θα συνήθως ονομάζεται HashMap σε άλλες γλώσσες) που είναι το άθροισμα ή τη συγχώνευση, της default_versionκαι years_dict, αλλά όταν ένας το κλειδί είναι παρούσα και στις δύο από αυτές, η τιμή από years_dictυπερισχύει - η οποία πληροί το βασικό όρο για ένα έτος που είναι σήμερα (δηλαδή, είναι μια χρονιά με μια αλλαγή σε αρχεία) και στα δύο.

Μετά από αυτό είναι παιχνιδάκι: anydict.pop (somekey) επιστρέφει την τιμή που αντιστοιχεί στο κλειδί (και επίσης αφαιρεί από anydict)? min (anydict) επιστρέφει το ελάχιστο κλειδί στο λεξικό. Σημειώστε το «φρουρού» ιδίωμα σε merged[max_year + 1] = None: αυτό λέει ότι η χρονιά «το ένα μετά το μέγιστο ένα» είναι πάντα θεωρείται ως αλλαγή ετών (με εικονική αξία κράτησης θέσης των Κανένας), έτσι ώστε η τελευταία σειρά των γραμμών είναι πάντα γραμμένο σωστά (με μέγιστο χρόνο της max_year + 1 - 1, που είναι, ακριβώς max_year, όπως είναι επιθυμητό).

Ο αλγόριθμος αυτός δεν είναι μέγιστη αποτελεσματική, ακριβώς απλούστερα! Κάνουμε min(merged)ξανά και ξανά, καθιστώντας O (N τετράγωνο) - Νομίζω ότι μπορούμε να διαθέσουμε ότι επειδή κάθε mergedπρέπει να έχει μερικές δεκάδες αλλαγή έτη κατ 'ανώτατο όριο, αλλά μια καθαρεύουσα θα αισθανθείς άσχημα. Φυσικά μπορούμε να παρουσιάσουμε ένα Ξ λύση (Ν logN) - μόνο ταξινομήσετε τα χρόνια μια για πάντα και να περπατήσετε αυτήν την αλληλουχία για να πάρει τις διαδοχικές τιμές next_change. Απλά για την πληρότητα ...:

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

Εδώ sortedδίνει μια λίστα με τα κλειδιά του mergedσε ταξινομημένη σειρά, και έχω αλλάξει την forκατάσταση για να περπατήσετε αυτήν τη λίστα από την αρχή μέχρι το τέλος (και αν δηλώσεις σε τίποτα εξόδου για πρώτη φορά μέσα). Ο φρουρός τώρα τεθεί σε default_version (γι 'αυτό είναι έξω από το βρόχο, για μια άλλη μικρή βελτιστοποίησης). Είναι αστείο να δούμε ότι αυτή η βελτιωμένη έκδοση (κυρίως επειδή λειτουργεί σε ελαφρώς υψηλότερο επίπεδο αφαίρεσης) αποδεικνύεται ότι είναι μικρότερα και πιο απλό από ό, τι τα προηγούμενα ;-).

Απαντήθηκε 05/07/2009 στις 22:57
πηγή χρήστη

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