Betrachten Sie das folgende Array:
/www/htdocs/1/sites/lib/abcdedd
/www/htdocs/1/sites/conf/xyz
/www/htdocs/1/sites/conf/abc/def
/www/htdocs/1/sites/htdocs/xyz
/www/htdocs/1/sites/lib2/abcdedd
Was ist die kürzeste und eleganteste Art, den gemeinsamen Basispfad zu erkennen - in diesem Fall
/www/htdocs/1/sites/
und entfernen Sie es von allen Elementen im Array?
lib/abcdedd
conf/xyz
conf/abc/def
htdocs/xyz
lib2/abcdedd
Antworten:
Schreiben Sie eine Funktion
longest_common_prefix
, die zwei Zeichenfolgen als Eingabe verwendet. Wenden Sie es dann in beliebiger Reihenfolge auf die Zeichenfolgen an, um sie auf ihr gemeinsames Präfix zu reduzieren. Da es assoziativ und kommutativ ist, spielt die Reihenfolge für das Ergebnis keine Rolle.Dies ist dasselbe wie für andere binäre Operationen wie zum Beispiel Addition oder größter gemeinsamer Divisor.
quelle
Laden Sie sie in eine Trie-Datenstruktur. Sehen Sie ausgehend vom übergeordneten Knoten, welcher untergeordnete Knoten mehr als eins zählt. Wenn Sie diesen magischen Knoten gefunden haben, zerlegen Sie einfach die übergeordnete Knotenstruktur und haben Sie den aktuellen Knoten als Root.
quelle
quelle
/usr/lib
und/usr/lib2
es wurde/usr/lib
als längster gemeinsamer Pfad angegeben/usr/
). Ich habe (hoffentlich) beides behoben.Nun, wenn man bedenkt, dass Sie
XOR
in dieser Situation die gemeinsamen Teile der Zeichenfolge finden können. Jedes Mal, wenn Sie zwei oder zwei Bytes identisch sind, erhalten Sie ein Nullbyte als Ausgabe. Das können wir also zu unserem Vorteil nutzen:Nach dieser einzelnen Schleife entspricht die
$length
Variable dem längsten gemeinsamen Basisteil zwischen den Zeichenfolgen. Dann können wir den gemeinsamen Teil aus dem ersten Element extrahieren:Und da hast du es. Als eine Funktion:
Beachten Sie, dass mehr als eine Iteration verwendet wird, diese Iterationen jedoch in Bibliotheken durchgeführt werden. In interpretierten Sprachen bedeutet dies einen enormen Effizienzgewinn ...
Wenn Sie nur vollständige Pfade möchten, müssen Sie das letzte
/
Zeichen abschneiden . So:Jetzt können zwei Saiten übermäßig geschnitten werden, z. B.
/foo/bar
und/foo/bar/baz
werden zugeschnitten/foo
. Aber ohne eine weitere Iterationsrunde hinzuzufügen, um festzustellen, ob das nächste Zeichen eines/
oder ein Ende der Zeichenfolge ist, sehe ich keinen Weg daran vorbei ...quelle
Ein naiver Ansatz wäre, die Pfade am zu explodieren
/
und nacheinander jedes Element in den Arrays zu vergleichen. ZB wäre das erste Element in allen Arrays leer, also wird es entfernt, das nächste Elementwww
, es ist in allen Arrays gleich, also wird es entfernt usw.Etwas wie (
ungetestet)Danach müssen Sie nur noch die Elemente
$exploded_paths
erneut implodieren :Welches gibt mir:
Dies ist möglicherweise nicht gut skalierbar;)
quelle
Ok, ich bin nicht sicher, ob dies kugelsicher ist, aber ich denke, es funktioniert:
Dadurch wird der erste Wert im Array als Referenzzeichenfolge verwendet. Dann wird die Referenzzeichenfolge durchlaufen und jedes Zeichen mit dem Zeichen der zweiten Zeichenfolge an derselben Position verglichen. Wenn ein Zeichen nicht übereinstimmt, wird die Referenzzeichenfolge auf die Position des Zeichens gekürzt und die nächste Zeichenfolge verglichen. Die Funktion gibt dann die kürzeste übereinstimmende Zeichenfolge zurück.
Die Leistung hängt von den angegebenen Zeichenfolgen ab. Je früher die Referenzzeichenfolge kürzer wird, desto schneller wird der Code beendet. Ich habe wirklich keine Ahnung, wie ich das in eine Formel einfügen soll.
Ich fand heraus, dass Artefactos Ansatz zum Sortieren der Saiten die Leistung erhöht. Hinzufügen
vor dem
array_reduce
wird die Leistung deutlich steigern.Beachten Sie auch, dass dies die längste übereinstimmende anfängliche Teilzeichenfolge zurückgibt , die vielseitiger ist, Ihnen jedoch nicht den gemeinsamen Pfad gibt . Du musst rennen
auf das Ergebnis. Und dann können Sie das Ergebnis verwenden, um die Werte zu entfernen
was geben sollte:
Feedback willkommen.
quelle
Sie können das Präfix am schnellsten entfernen, indem Sie jedes Zeichen nur einmal lesen:
quelle
Dies hat den Vorteil, keine lineare Zeitkomplexität zu haben; In den meisten Fällen ist die Sortierung jedoch definitiv nicht die Operation, die mehr Zeit in Anspruch nimmt.
Grundsätzlich ist der clevere Teil (zumindest konnte ich keinen Fehler finden), dass Sie nach dem Sortieren nur den ersten Pfad mit dem letzten vergleichen müssen.
quelle
EDIT Variante meiner ursprünglichen Methode mit einem array_walk zum Neuerstellen des Arrays
BEARBEITEN
Die effizienteste und eleganteste Antwort besteht wahrscheinlich darin, Funktionen und Methoden aus jeder der bereitgestellten Antworten zu übernehmen
quelle
Ich würde
explode
die Werte basierend auf dem / verwenden und dann verwendenarray_intersect_assoc
, um die gemeinsamen Elemente zu erkennen und sicherzustellen, dass sie den richtigen entsprechenden Index im Array haben. Das resultierende Array könnte neu kombiniert werden, um den gemeinsamen Pfad zu erzeugen.Dies ist nicht getestet, aber die Idee ist, dass das
$commonPath
Array immer nur die Elemente des Pfads enthält, die in allen Pfadarrays enthalten waren, die mit ihm verglichen wurden. Wenn die Schleife abgeschlossen ist, kombinieren wir sie einfach mit /, um das Wahre zu erhalten$commonPath
Update Wie von Felix Kling hervorgehoben,
array_intersect
werden Pfade mit gemeinsamen Elementen, aber in unterschiedlicher Reihenfolge, nicht berücksichtigt. Um dies zu lösen, habe icharray_intersect_assoc
stattdessen verwendetarray_intersect
Update Hinzugefügter Code, um den allgemeinen Pfad (oder tetris it!) Auch aus dem Array zu entfernen.
quelle
/a/b/c/d
und/d/c/b/a
. Gleiche Elemente, unterschiedliche Wege.Das Problem kann vereinfacht werden, wenn es nur aus dem String-Vergleichswinkel betrachtet wird. Dies ist wahrscheinlich schneller als das Aufteilen von Arrays:
quelle
Vielleicht
os.path.commonprefix(m)
würde es funktionieren, den von Python verwendeten Algorithmus zu portieren ?Das heißt, äh ... so etwas wie
Danach können Sie jedes Element der ursprünglichen Liste mit der Länge des gemeinsamen Präfixes als Startoffset unterteilen.
quelle
Ich werde meinen Hut in den Ring werfen ...
Verwendung:
quelle
Nun, hier gibt es bereits einige Lösungen, aber nur weil es Spaß gemacht hat:
Ausgabe:
quelle
Dies funktioniert gut ... ähnlich wie Mark Baker, verwendet jedoch str_replace
quelle
Wahrscheinlich zu naiv und noobisch, aber es funktioniert. Ich habe diesen Algorithmus verwendet :
Ausgabe:
:) :)
quelle
/www/htdocs/1/sites/conf/
als allgemeine Übereinstimmung gefunden. Der Algorithmus sucht auch nach Teilzeichenfolgen, die an einer beliebigen Stelle in der Zeichenfolge beginnen. Bei dieser Frage wissen Sie jedoch, dass Sie an Position 0 beginnen können, was die Arbeit erheblich vereinfacht.