Wie kann am besten getestet werden, ob eine Liste in Clojure einen bestimmten Wert enthält?
Insbesondere das Verhalten von contains?
verwirrt mich derzeit:
(contains? '(100 101 102) 101) => false
Ich könnte natürlich eine einfache Funktion schreiben, um die Liste zu durchlaufen und auf Gleichheit zu testen, aber es muss sicher einen Standardweg geben, um dies zu tun?
data-structures
clojure
mikera
quelle
quelle
Antworten:
Ah,
contains?
... angeblich eine der fünf häufigsten FAQs zu: Clojure.Es wird nicht geprüft, ob eine Sammlung einen Wert enthält. Es wird geprüft, ob ein Element mit abgerufen werden kann
get
oder mit anderen Worten, ob eine Sammlung einen Schlüssel enthält. Dies macht Sinn , für Sätze (die als zu machen keinen Unterschied zwischen Schlüssel und Werte betrachtet werden können), Karten (so(contains? {:foo 1} :foo)
isttrue
) und Vektoren (aber beachten Sie, dass(contains? [:foo :bar] 0)
isttrue
, dass die Schlüssel hier Indizes sind und der betreffende Vektor die "enthält" Index0
!).Um die Verwirrung zu verstärken, kehrt es in Fällen, in denen es keinen Sinn macht, anzurufenAktualisieren: In Clojure wird ≥ 1,5contains?
, einfach zurückfalse
. das ist es, was in(contains? :foo 1)
und auch passiert(contains? '(100 101 102) 101)
.contains?
geworfen, wenn ein Objekt eines Typs übergeben wird, der den beabsichtigten "Schlüsselmitgliedschaftstest" nicht unterstützt.Der richtige Weg, um das zu tun, was Sie versuchen, ist wie folgt:
Bei der Suche nach einem von mehreren Artikeln können Sie einen größeren Satz verwenden. bei der Suche nach
false
/nil
, können Siefalse?
/nil?
- weil(#{x} x)
Renditenx
, so(#{nil} nil)
istnil
; Wenn Sie nach einem von mehreren Elementen suchen, von denen einige möglicherweisefalse
oder sindnil
, können Sie sie verwenden(Beachten Sie, dass die Elemente
zipmap
in jeder Art von Sammlung weitergegeben werden können.)quelle
(some #{101} '(100 101 102))
, dass "dies meistens funktioniert". Ist es nicht fair zu sagen, dass es immer funktioniert? Ich verwende Clojure 1.4 und die Dokumentation verwendet diese Art von Beispiel. Es funktioniert für mich und macht Sinn. Gibt es einen Sonderfall, in dem es nicht funktioniert?false
oder suchennil
- siehe folgenden Absatz. In Clojure 1.5-RC1 wirdcontains?
eine Ausnahme ausgelöst, wenn eine nicht verschlüsselte Sammlung als Argument angegeben wird. Ich nehme an, ich werde diese Antwort bearbeiten, wenn die endgültige Version herauskommt.Hier ist mein Standard-Util für den gleichen Zweck:
quelle
nil
und verarbeitetfalse
. Warum ist das nicht Teil von Clojure / Core?seq
könnte vielleicht umbenannt werdencoll
, um Verwechslungen mit der Funktion zu vermeidenseq
?seq
im Körper nicht verwenden, besteht kein Konflikt mit dem gleichnamigen Parameter. Sie können die Antwort jedoch jederzeit bearbeiten, wenn Sie der Meinung sind, dass das Umbenennen das Verständnis erleichtern würde.(boolean (some #{elm} coll))
wenn Sie sich keine Sorgen machen müssennil
oderfalse
.Sie können Java-Methoden jederzeit mit der Syntax .methodName aufrufen.
quelle
contains?
, schlug Qc Na ihn mit einem Bô und sagte: "Blöder Schüler! Man muss erkennen, dass es keinen Löffel gibt. Es ist alles nur Java darunter! Verwenden Sie die Punktnotation." In diesem Moment wurde Anton erleuchtet.Ich weiß, dass ich etwas spät dran bin, aber was ist mit:
Endlich in Clojure 1.4 gibt true aus :)
quelle
(set '(101 102 103))
ist das gleiche wie%{101 102 103}
. Ihre Antwort kann also wie folgt geschrieben werden(contains? #{101 102 103} 102)
.'(101 102 103)
in einen Satz erforderlich ist .Funktioniert, aber unten ist besser:
quelle
Für das, was es wert ist, ist dies meine einfache Implementierung einer Include-Funktion für Listen:
quelle
(defn list-contains? [pred coll value] (let [s (seq coll)] (if s (if (pred (first s) value) true (recur (rest s) value)) false)))
Wenn Sie einen Vektor oder eine Liste haben und überprüfen möchten, ob ein Wert darin enthalten ist, werden Sie feststellen, dass
contains?
dies nicht funktioniert. Michał hat bereits erklärt warum .In diesem Fall können Sie vier Dinge ausprobieren:
Überlegen Sie, ob Sie wirklich einen Vektor oder eine Liste benötigen. Wenn Sie stattdessen ein Set verwenden ,
contains?
funktioniert dies.Verwenden Sie
some
das Ziel wie folgt in einem Satz:Die Verknüpfung zum Festlegen der Funktion funktioniert nicht, wenn Sie nach einem falschen Wert (
false
odernil
) suchen .In diesen Fällen sollten Sie die integrierte Prädikatfunktion für diesen Wert verwenden,
false?
odernil?
:Wenn Sie diese Art der Suche häufig durchführen müssen, schreiben Sie eine Funktion dafür :
In Michałs Antwort finden Sie auch Möglichkeiten, um zu überprüfen, ob mehrere Ziele in einer Sequenz enthalten sind.
quelle
Hier ist eine kurze Funktion meiner Standarddienstprogramme, die ich für diesen Zweck verwende:
quelle
Hier ist die klassische Lisp-Lösung:
quelle
some
verfügbaren Kerne möglicherweise parallel sind.Ich habe auf der jg-faustus- Version von "list-enthält?" Es sind jetzt beliebig viele Argumente erforderlich.
quelle
Es ist so einfach wie die Verwendung eines Sets - ähnlich wie bei Karten können Sie es einfach an der Funktionsposition ablegen. Es wird als Wert ausgewertet, wenn in der Menge (was wahr ist) oder
nil
(was falsch ist):Wenn Sie mit einem Vektor / einer Liste mit angemessener Größe vergleichen, die Sie erst zur Laufzeit haben, können Sie auch die folgende
set
Funktion verwenden:quelle
Die empfohlene Methode ist die Verwendung
some
mit einem Set - siehe Dokumentation zuclojure.core/some
.Sie können dann
some
innerhalb eines echten wahr / falsch-Prädikats verwenden, zquelle
if
true
undfalse
?some
gibt bereits true-ish- und false-ish-Werte zurück.quelle
Beispielverwendung (welche? [1 2 3] 3) oder (welche? # {1 2 3} 4 5 3)
quelle
Da Clojure auf Java basiert, können Sie das genauso einfach aufrufen
.indexOf
Java-Funktion . Diese Funktion gibt den Index eines Elements in einer Auflistung zurück. Wenn dieses Element nicht gefunden werden kann, wird -1 zurückgegeben.Wenn wir dies nutzen, können wir einfach sagen:
quelle
Das Problem mit der "empfohlenen" Lösung ist, dass es zu Unterbrechungen kommt, wenn der gesuchte Wert "Null" ist. Ich bevorzuge diese Lösung:
quelle
Zu diesem Zweck gibt es in der Tupelo-Bibliothek praktische Funktionen . Insbesondere sind die Funktionen
contains-elem?
,contains-key?
undcontains-val?
sind sehr nützlich. Die vollständige Dokumentation finden Sie in den API-Dokumenten .contains-elem?
ist die allgemeinste und ist für Vektoren oder andere Clojure gedachtseq
:Hier sehen wir, dass für einen ganzzahligen Bereich oder einen gemischten Vektor
contains-elem?
sowohl für vorhandene als auch für nicht vorhandene Elemente in der Sammlung wie erwartet funktioniert. Für Karten können wir auch nach einem beliebigen Schlüssel-Wert-Paar suchen (ausgedrückt als len-2-Vektor):Es ist auch einfach, einen Satz zu suchen:
Bei Karten und Sets ist es einfacher (und effizienter),
contains-key?
einen Karteneintrag oder ein Set-Element zu finden:Für Karten können Sie auch nach Werten suchen mit
contains-val?
:Wie im Test zu sehen ist, funktioniert jede dieser Funktionen bei der Suche nach
nil
Werten ordnungsgemäß .quelle
Andere Option:
Verwenden Sie java.util.Collection # enthält ():
quelle