Nehmen wir an, ich habe ein Array und ich weiß, dass ich viel tun werde. "Enthält das Array X?" prüft. Der effizienteste Weg, dies zu tun, besteht darin, dieses Array in einen Hash umzuwandeln, in dem die Schlüssel die Elemente des Arrays sind, und dann können Sie einfach sagen
if ($ hash {X}) {...}
Gibt es eine einfache Möglichkeit, diese Array-zu-Hash-Konvertierung durchzuführen? Idealerweise sollte es vielseitig genug sein, um ein anonymes Array zu verwenden und einen anonymen Hash zurückzugeben.
Die Syntax hier, in der Sie sich mit einem auf den Hash beziehen,
@
ist ein Hash-Slice. Wir sagen im Grunde,$hash{$keys[0]}
AND$hash{$keys[1]}
AND$hash{$keys[2]}
... ist eine Liste auf der linken Seite von =, ein l-Wert, und wir weisen dieser Liste zu, die tatsächlich in den Hash eingeht und die Werte für alle benannten Schlüssel festlegt. In diesem Fall habe ich nur einen Wert angegeben, damit dieser Wert$hash{$keys[0]}
eingegeben wird, und die anderen Hash-Einträge werden alle automatisch mit undefinierten Werten belebt (zum Leben erweckt). [Mein ursprünglicher Vorschlag hier war, den Ausdruck = 1 zu setzen, wodurch dieser eine Schlüssel auf 1 und der andere auf 1 gesetzt worden wäreundef
. Ich habe es aus Gründen der Konsistenz geändert, aber wie wir weiter unten sehen werden, spielen die genauen Werte keine Rolle.]Wenn Sie feststellen, dass der l-Wert, der Ausdruck auf der linken Seite des =, eine Liste ist, die aus dem Hash erstellt wurde, macht es Sinn, warum wir das verwenden
@
. [Außer ich denke, das wird sich in Perl 6 ändern.]Die Idee hier ist, dass Sie den Hash als Set verwenden. Was zählt, ist nicht der Wert, den ich zuweise; Es ist nur die Existenz der Schlüssel. Was Sie also tun möchten, ist nicht so etwas wie:
stattdessen:
Es ist tatsächlich effizienter, nur eine
exists
Prüfung durchzuführen, als sich um den Wert im Hash zu kümmern, obwohl für mich hier nur das Konzept wichtig ist, dass Sie eine Menge nur mit den Schlüsseln des Hash darstellen. Außerdem hat jemand darauf hingewiesen, dassundef
wir durch die Verwendung als Wert hier weniger Speicherplatz verbrauchen, als wenn wir einen Wert zuweisen würden. (Und außerdem weniger Verwirrung stiften, da der Wert keine Rolle spielt und meine Lösung nur dem ersten Element im Hash einen Wert zuweisen und die anderenundef
belassen würde. Einige andere Lösungen drehen Wagenräder, um eine Reihe von Werten zu erstellen, in die sie gehen sollen der Hash; völlig verschwendete Mühe).quelle
= ()
, nicht= undef
nur aus Gründen der Konsistenz bei der impliziten Verwendung von undef für alle Werte, nicht nur für alle nach dem ersten. (Wie in diesen Kommentaren gezeigt, ist es zu einfach, das zu sehenundef
und zu denken, dass es einfach in 1 geändert werden kann und alle Hash-Werte beeinflusst.)Beachten Sie, dass
if ( exists $hash{ key } )
Sie das Kurze und Süße verwenden können , wenn das Tippen für Sie nicht zu viel Arbeit ist (was ich lieber verwende, da es wirklich um das Vorhandensein eines Schlüssels als um die Wahrhaftigkeit seines Werts geht)quelle
Das habe ich immer gedacht
war zumindest nett und lesbar / wartbar.
quelle
Hier besteht die Voraussetzung, dass der effizienteste Weg ist, viele "Enthält das Array X?" Bei Checks wird das Array in einen Hash konvertiert. Die Effizienz hängt von der knappen Ressource ab, oft von Zeit, manchmal von Platz und manchmal von Programmieraufwand. Sie verdoppeln mindestens den Speicherbedarf, indem Sie gleichzeitig eine Liste und einen Hash der Liste führen. Außerdem schreiben Sie mehr Originalcode, den Sie testen, dokumentieren usw. müssen.
Als Alternative Blick auf die Liste :: MoreUtils Modul, speziell die Funktionen
any()
,none()
,true()
undfalse()
. Sie alle nehmen einen Block als Bedingung und eine Liste als Argument, ähnlichmap()
undgrep()
:print "At least one value undefined" if any { !defined($_) } @list;
Ich führte einen Schnelltest durch, lud die Hälfte von / usr / share / dict / words in ein Array (25000 Wörter) und suchte dann nach elf Wörtern, die aus dem gesamten Wörterbuch (alle 5000. Wörter) im Array ausgewählt wurden, wobei beide Arrays verwendet wurden -to-Hash-Methode und die
any()
Funktion von List :: MoreUtils.Unter Perl 5.8.8, das aus dem Quellcode erstellt wurde, wird die Array-to-Hash-Methode fast 1100-mal schneller ausgeführt als die
any()
Methode (1300-mal schneller unter Ubuntu 6.06s Perl 5.8.7).Dies ist jedoch nicht die ganze Geschichte - die Umwandlung von Array in Hash dauert etwa 0,04 Sekunden, was in diesem Fall die Zeiteffizienz der Array-zu-Hash-Methode auf 1,5x-2x schneller als die
any()
Methode verringert . Immer noch gut, aber bei weitem nicht so herausragend.Mein Bauchgefühl ist, dass die Array-to-Hash-Methode
any()
in den meisten Fällen besser abschneiden wird, aber ich würde mich viel besser fühlen, wenn ich solideere Metriken hätte (viele Testfälle, anständige statistische Analysen, vielleicht einige große). O algorithmische Analyse jeder Methode usw.) Abhängig von Ihren Anforderungen kann List :: MoreUtils eine bessere Lösung sein. Es ist sicherlich flexibler und erfordert weniger Codierung. Denken Sie daran, vorzeitige Optimierung ist eine Sünde ... :)quelle
List::MoreUtils
kann je nach Anwendungsfall eine geeignete Methode sein oder auch nicht. Ihr Anwendungsfall kann viele Suchvorgänge enthalten. andere vielleicht nicht. Der Punkt ist, dass sowohl die Umwandlung von Array in Hash als auchList::MoreUtils
das zugrunde liegende Problem der Bestimmung der Mitgliedschaft gelöst werden; Wenn Sie mehrere Ansätze kennen, können Sie die beste Methode für Ihren speziellen Anwendungsfall auswählen.In Perl 5.10 gibt es den magischen Operator ~~:
Siehe hier: http://dev.perl.org/perl5/news/2007/perl-5.10.0.html
quelle
Der Vollständigkeit halber auch erwähnenswert, meine übliche Methode, dies mit 2 Arrays gleicher Länge zu tun,
@keys
und@vals
die Sie bevorzugen würden, war ein Hash ...my %hash = map { $keys[$_] => $vals[$_] } (0..@keys-1);
quelle
@keys-1
ist$#keys
.Raldis Lösung kann bis dahin verschärft werden (das '=>' vom Original ist nicht erforderlich):
Diese Technik kann auch verwendet werden, um Textlisten in Hashes umzuwandeln:
Wenn Sie eine Wertezeile wie die folgende haben: "foo = 1, bar = 2, baz = 3", können Sie Folgendes tun:
[BEARBEITEN, um einzuschließen]
Eine andere angebotene Lösung (die zwei Zeilen umfasst) ist:
quelle
Sie können auch Perl6 :: Junction verwenden .
quelle
Wenn Sie viele satztheoretische Operationen ausführen, können Sie auch Set :: Scalar oder ein ähnliches Modul verwenden. Dann
$s = Set::Scalar->new( @array )
wird das Set für Sie erstellt - und Sie können es abfragen mit :$s->contains($m)
.quelle
Sie können den Code in eine Unterroutine einfügen, wenn Sie Ihren Namespace nicht verschmutzen möchten.
Oder noch besser:
Wenn Sie wirklich eine Array-Referenz übergeben möchten:
quelle
%hash = map{ $_, undef } @keylist
gibt (beachten Sie, dass wiederholte Tasten den Wert an der größten Position im Array erhalten - dh 8-> 2 und nicht 6)
quelle
Vielleicht möchten Sie auch Tie :: IxHash ausprobieren , das geordnete assoziative Arrays implementiert. Auf diese Weise können Sie beide Arten von Suchvorgängen (Hash und Index) für eine Kopie Ihrer Daten durchführen.
quelle