परीक्षण करें कि क्या किसी सूची में क्लोजर में एक विशिष्ट मूल्य है


163

यह जांचने का सबसे अच्छा तरीका है कि क्या किसी सूची में क्लोजर में दिए गए मूल्य हैं?

विशेष रूप से, का व्यवहार contains?वर्तमान में मुझे भ्रमित कर रहा है:

(contains? '(100 101 102) 101) => false

मैं स्पष्ट रूप से समानता के लिए सूची और परीक्षण को पार करने के लिए एक सरल कार्य लिख सकता था, लेकिन निश्चित रूप से ऐसा करने का एक मानक तरीका होना चाहिए?


7
अजीब वास्तव में, शामिल हैं? Clojure में सबसे भ्रामक रूप से नामांकित समारोह होना चाहिए :) यहाँ उम्मीद है कि Clojure 1.3 में इसे मुख्य-कुंजी का नाम दिया जाएगा? या इसी के समान।
jg-faustus

4
मुझे लगता है कि अब कई बार मौत से बात की जाती है। शामिल? बदलेगा नहीं। यहाँ देखें: groups.google.com/group/clojure/msg/f2585c149cd0465d और groups.google.com/group/clojure/msg/985478420223ecdf
kotarak

1
@kotarak लिंक के लिए धन्यवाद! मैं वास्तव में रिच के साथ यहां के उपयोग के संदर्भ में सहमत हूं? नाम हालांकि मुझे लगता है कि सूची या अनुक्रम पर लागू होने पर एक त्रुटि को फेंकने के लिए इसे बदल दिया जाना चाहिए
mikera

जवाबों:


204

आह, contains?... माना जाता है कि शीर्ष पांच में से एक सामान्य प्रश्न: क्लोजर।

यह जाँच नहीं करता है कि क्या संग्रह में कोई मूल्य है; यह जाँचता है कि क्या किसी आइटम के साथ getया दूसरे शब्दों में प्राप्त किया जा सकता है , क्या संग्रह में कोई कुंजी है। इस सेट (जो कुंजी और मूल्यों के बीच कोई फर्क बनाने के बारे में सोचा जा सकता है), नक्शे (ताकि के लिए समझ में आता है (contains? {:foo 1} :foo)है true) और वैक्टर (लेकिन ध्यान दें कि (contains? [:foo :bar] 0)है true, क्योंकि चाबियाँ यहाँ सूचकांक कर रहे हैं और प्रश्न में वेक्टर "में" है सूचकांक 0!)।

भ्रम में जोड़ने के लिए, उन मामलों में जहां यह कॉल करने के लिए समझ में नहीं आता है contains?, यह बस वापस आ जाता है false; यह है कि क्या में होता है (contains? :foo 1) और यह भी (contains? '(100 101 102) 101) अद्यतन: क्लोजर में In 1.5 contains?फेंकता है जब एक प्रकार की वस्तु सौंपी जाती है जो इच्छित "कुंजी सदस्यता" परीक्षण का समर्थन नहीं करती है।

आप जो करने की कोशिश कर रहे हैं, उसका सही तरीका इस प्रकार है:

; most of the time this works
(some #{101} '(100 101 102))

वस्तुओं के एक समूह की खोज करते समय, आप एक बड़े सेट का उपयोग कर सकते हैं; false/ की खोज करते समय nil, आप उपयोग कर सकते हैं false?/ nil?- क्योंकि (#{x} x)रिटर्न x, इस प्रकार (#{nil} nil)है nil; कई वस्तुओं में से किसी एक को खोजते समय, जिनमें से कुछ हो सकता है falseया nilआप उपयोग कर सकते हैं

(some (zipmap [...the items...] (repeat true)) the-collection)

(ध्यान दें कि आइटम zipmapकिसी भी प्रकार के संग्रह में पारित किए जा सकते हैं ।)


धन्यवाद मिशल - आप हमेशा की तरह क्लोजर ज्ञान के एक फ़ॉन्ट हैं! ऐसा लगता है कि मैं इस मामले में अपना स्वयं का कार्य लिखने जा रहा हूं ... यह मुझे थोड़ा आश्चर्यचकित करता है कि मूल भाषा में पहले से ही कोई नहीं है।
19

4
जैसा कि मिशल ने कहा - कोर में पहले से ही एक फंक्शन है जो आप की इच्छा करता है: कुछ।
कोट्टारक

2
ऊपर, मीकल ने टिप्पणी करते (some #{101} '(100 101 102))हुए कहा कि "अधिकांश समय यह काम करता है"। क्या यह कहना उचित नहीं है कि यह हमेशा काम करता है? मैं क्लीज्योर 1.4 का उपयोग कर रहा हूं और प्रलेखन इस तरह के उदाहरण का उपयोग करता है। यह मेरे लिए काम करता है और समझ में आता है। क्या किसी प्रकार का विशेष मामला है जहां यह काम नहीं करता है?
डेविड जे।

7
@DavidJames: यदि आप की उपस्थिति के लिए जाँच कर रहे हैं तो यह काम नहीं करता है - falseया nilनिम्नलिखित पैराग्राफ को देखें। एक अलग नोट पर, क्लोजर में 1.5-RC1 contains?एक अपवाद के रूप में दिया जाता है जब एक गैर-कुंजी संग्रह को एक तर्क के रूप में दिया जाता है। मुझे लगता है कि जब अंतिम रिलीज होगी तब मैं इस उत्तर को संपादित करूंगा।
मीकल मार्केज

1
यह बेवकूफी है! एक संग्रह का मुख्य अंतर सदस्यता संबंध है। यह संग्रह के लिए सबसे महत्वपूर्ण कार्य होना चाहिए था। en.wikipedia.org/wiki/Set_(mathematics)#Membership
jgomo3

132

यहाँ एक ही उद्देश्य के लिए मेरा मानक उपयोग है:

(defn in? 
  "true if coll contains elm"
  [coll elm]  
  (some #(= elm %) coll))

36
यह सबसे सरल और सबसे सुरक्षित उपाय है, क्योंकि यह भी nilऔर जैसे झूठे मूल्यों को संभालता है false। अब यह क्लोजर / कोर का हिस्सा क्यों नहीं है?
स्टियन सोइलैंड-रेयेस

2
seqशायद collसमारोह के साथ भ्रम से बचने के लिए , इसका नाम बदला जा सकता है seq?
nha

3
@ न्हा आप ऐसा कर सकते हैं, हाँ। यहां कोई फर्क नहीं पड़ता: चूंकि हम seqशरीर के अंदर फ़ंक्शन का उपयोग नहीं कर रहे हैं , इसलिए समान नाम के पैरामीटर के साथ कोई संघर्ष नहीं है। लेकिन बेझिझक जवाब को संपादित करें यदि आपको लगता है कि नाम बदलने से समझने में आसानी होगी।
jg-faustus

1
यह ध्यान देने योग्य है कि यह 3-4x धीमा हो सकता है (boolean (some #{elm} coll))अगर आपको इसके बारे में चिंता करने की ज़रूरत नहीं है nilया नहीं false
neverfox

2
@AviFlax मैं के बारे में सोच रहा था clojure.org/guides/threading_macros , है, जहां यह कहते हैं, "परंपरा के मुताबिक, प्रमुख कार्यों कि दृश्यों पर काम उम्मीद अपने पिछले तर्क के रूप में अनुक्रम। तदनुसार, नक्शा, फिल्टर, निकालें, को कम युक्त पाइपलाइनों, में आदि आमतौर पर - >> मैक्रो के लिए कॉल करें। " लेकिन मुझे लगता है कि सम्मेलन उन कार्यों के बारे में अधिक है जो अनुक्रमों और रिटर्न अनुक्रमों पर काम करते हैं।
जॉन वाइसमैन

18

आप हमेशा .methodName सिंटैक्स के साथ जावा विधियों को कॉल कर सकते हैं।

(.contains [100 101 102] 101) => true

5
IMHO यह सबसे अच्छा जवाब है। बहुत बुरा क्लोजर होता है? इतना भ्रमित नाम है।
मिककोम

1
आदरणीय मास्टर Qc Na अपने छात्र एंटोन के साथ चल रहे थे। जब एंटोन ने उसे कुछ शुरुआत की समस्या के बारे में बताया contains?, Qc Na ने उसे एक बीओओ के साथ मारा और कहा: "मूर्ख छात्र! आपको महसूस करना होगा कि कोई चम्मच नहीं है। यह सब सिर्फ जावा के नीचे है! डॉट नोटेशन का उपयोग करें।" उस क्षण में, एंटोन प्रबुद्ध हो गया।
डेविड टोनहोफर

17

मुझे पता है कि मुझे थोड़ी देर हो गई है, लेकिन इसके बारे में क्या:

(contains? (set '(101 102 103)) 102)

Clojure में अंत में 1.4 आउटपुट सही है :)


3
(set '(101 102 103))के रूप में ही है %{101 102 103}। तो आपके उत्तर के रूप में लिखा जा सकता है (contains? #{101 102 103} 102)
डेविड जे।

4
इससे मूल सूची '(101 102 103)के एक सेट में रूपांतरण की आवश्यकता का नुकसान होता है ।
डेविड जे।

12
(not= -1 (.indexOf '(101 102 103) 102))

काम करता है, लेकिन नीचे बेहतर है:

(some #(= 102 %) '(101 102 103)) 

7

इसके लायक क्या है, यह सूचियों के लिए एक सम्‍मिलित फ़ंक्शन का मेरा सरल कार्यान्वयन है:

(defn list-contains? [coll value]
  (let [s (seq coll)]
    (if s
      (if (= (first s) value) true (recur (rest s) value))
      false)))

क्या हम तर्क के रूप में विधेय के लिए पूछ सकते हैं? कुछ पाने के लिए:(defn list-contains? [pred coll value] (let [s (seq coll)] (if s (if (pred (first s) value) true (recur (rest s) value)) false)))
रफी पानॉयन

6

यदि आपके पास एक वेक्टर या सूची है और यह जांचना चाहते हैं कि क्या इसमें कोई मूल्य निहित है, तो आप पाएंगे कि contains?यह काम नहीं करता है। मिशेल ने पहले ही बताया है कि क्यों

; does not work as you might expect
(contains? [:a :b :c] :b) ; = false

इस मामले में आप चार चीजें आज़मा सकते हैं:

  1. विचार करें कि क्या आपको वास्तव में एक वेक्टर या सूची की आवश्यकता है। यदि आप इसके बजाय एक सेट का उपयोगcontains? करते हैं , तो काम करेगा।

    (contains? #{:a :b :c} :b) ; = true
  2. someइस प्रकार, लक्ष्य को सेट में लपेटकर उपयोग करें :

    (some #{:b} [:a :b :c]) ; = :b, which is truthy
  3. यदि आप एक गलत मान ( falseया nil) के लिए खोज कर रहे हैं, तो सेट-फ़ंक्शन फ़ंक्शन शॉर्टकट काम नहीं करेगा ।

    ; will not work
    (some #{false} [true false true]) ; = nil

    इन मामलों में, आपको उस मूल्य के लिए अंतर्निहित विधेय समारोह का उपयोग करना चाहिए , false?या nil?:

    (some false? [true false true]) ; = true
  4. यदि आपको इस तरह की खोज करने की आवश्यकता है, तो इसके लिए एक फ़ंक्शन लिखें :

    (defn seq-contains? [coll target] (some #(= target %) coll))
    (seq-contains? [true false true] false) ; = true

इसके अलावा, कई तरीकों से किसी भी लक्ष्य को एक अनुक्रम में समाहित करने के तरीके के लिए मिशेल का जवाब देखें ।


5

यहाँ मेरी मानक उपयोगिताओं का एक त्वरित कार्य है जिसे मैं इस उद्देश्य के लिए उपयोग करता हूं:

(defn seq-contains?
  "Determine whether a sequence contains a given item"
  [sequence item]
  (if (empty? sequence)
    false
    (reduce #(or %1 %2) (map #(= %1 item) sequence))))

हाँ, आपके पास यह फायदा है कि जैसे ही यह पूरा क्रम को जारी रखने के बजाय एक मैच ढूंढता है, वैसे ही रुक जाएगा।
G__

5

यहाँ क्लासिक लिस्प समाधान है:

(defn member? [list elt]
    "True if list contains at least one instance of elt"
    (cond 
        (empty? list) false
        (= (first list) elt) true
        true (recur (rest list) elt)))

4
ठीक है, क्लोजर में खराब समाधान का कारण यह है कि यह एक प्रोसेसर पर स्टैक को फिर से जमा करता है। एक बेहतर क्लोजर सॉल्यूशन है <pre> (डिफेक्ट मेंबर? [Elt col] (कुछ # (= elt%) col)) </ pre> ऐसा इसलिए someहै क्योंकि संभावित रूप से उपलब्ध कोर के समानांतर है।
सिमोन ब्रुक

4

मैंने "सूची- सम्‍मिलित ?" के jg-faustus वर्जन पर बनाया है । अब यह किसी भी प्रकार की बहस करता है।

(defn list-contains?
([collection value]
    (let [sequence (seq collection)]
        (if sequence (some #(= value %) sequence))))
([collection value & next]
    (if (list-contains? collection value) (apply list-contains? collection next))))

2

यह एक सेट का उपयोग करने के समान सरल है - नक्शे के समान, आप इसे फ़ंक्शन स्थिति में छोड़ सकते हैं। यह उस मूल्य का मूल्यांकन करता है यदि सेट में (जो nilसत्य है ) या (जो कि गलत है):

(#{100 101 102} 101) ; 101
(#{100 101 102} 99) ; nil

यदि आप एक उचित आकार के वेक्टर / सूची के खिलाफ जाँच कर रहे हैं, तो आपके पास रनटाइम तक नहीं होगा, तो आप setफ़ंक्शन का उपयोग भी कर सकते हैं :

; (def nums '(100 101 102))
((set nums) 101) ; 101

1

अनुशंसित तरीका someसेट के साथ उपयोग करना है - के लिए प्रलेखन देखें clojure.core/some

फिर आप someएक वास्तविक सच / झूठे विधेय के भीतर उपयोग कर सकते हैं , जैसे

(defn in? [coll x] (if (some #{x} coll) true false))

क्यों if trueऔर false? someपहले से ही सच्चे-ईश और झूठे-ईश मान लौटाता है।
२५'१३

किस बारे में (कुछ # {nil} [nil])? यह शून्य को लौटाएगा जिसे असत्य में बदल दिया जाएगा।
वी किउ

1
(defn in?
  [needle coll]
  (when (seq coll)
    (or (= needle (first coll))
        (recur needle (next coll)))))

(defn first-index
  [needle coll]
  (loop [index 0
         needle needle
         coll coll]
    (when (seq coll)
      (if (= needle (first coll))
        index
        (recur (inc index) needle (next coll))))))

1
(defn which?
 "Checks if any of elements is included in coll and says which one
  was found as first. Coll can be map, list, vector and set"
 [ coll & rest ]
 (let [ncoll (if (map? coll) (keys coll) coll)]
    (reduce
     #(or %1  (first (filter (fn[a] (= a %2))
                           ncoll))) nil rest )))

उदाहरण का उपयोग (जो? [1 2 3] 3) या (जो? # {1 2 3} 4 5 3)


अभी भी इसके लिए कोई भाषा-कोर आपूर्ति समारोह नहीं है?
Matanster

1

चूंकि Clojure जावा पर बनाया गया है, आप आसानी से .indexOfजावा फ़ंक्शन को कॉल कर सकते हैं । यह फ़ंक्शन किसी संग्रह में किसी भी तत्व के सूचकांक को लौटाता है, और यदि यह तत्व नहीं खोज पाता है, तो -1 देता है।

इसका उपयोग हम बस कह सकते हैं:

(not= (.indexOf [1 2 3 4] 3) -1)
=> true

0

'अनुशंसित' समाधान के साथ समस्या यह है कि जब आप जो मूल्य मांग रहे हैं वह '' शून्य '' है। मैं इस समाधान को पसंद करता हूं:

(defn member?
  "I'm still amazed that Clojure does not provide a simple member function.
   Returns true if `item` is a member of `series`, else nil."
  [item series]
  (and (some #(= item %) series) true))

0

टुपेलो पुस्तकालय में इस उद्देश्य के लिए सुविधाजनक कार्य हैं । विशेष रूप से, कार्यों contains-elem?, contains-key?और contains-val?बहुत उपयोगी हैं। पूर्ण दस्तावेज़ एपीआई डॉक्स में मौजूद है

contains-elem?सबसे सामान्य है और वैक्टर या किसी अन्य क्लोजर के लिए अभिप्रेत है seq:

  (testing "vecs"
    (let [coll (range 3)]
      (isnt (contains-elem? coll -1))
      (is   (contains-elem? coll  0))
      (is   (contains-elem? coll  1))
      (is   (contains-elem? coll  2))
      (isnt (contains-elem? coll  3))
      (isnt (contains-elem? coll  nil)))

    (let [coll [ 1 :two "three" \4]]
      (isnt (contains-elem? coll  :no-way))
      (isnt (contains-elem? coll  nil))
      (is   (contains-elem? coll  1))
      (is   (contains-elem? coll  :two))
      (is   (contains-elem? coll  "three"))
      (is   (contains-elem? coll  \4)))

    (let [coll [:yes nil 3]]
      (isnt (contains-elem? coll  :no-way))
      (is   (contains-elem? coll  :yes))
      (is   (contains-elem? coll  nil))))

यहां हम देखते हैं कि पूर्णांक श्रेणी या मिश्रित वेक्टर के लिए, contains-elem?संग्रह में मौजूदा और गैर-मौजूद दोनों तत्वों के लिए अपेक्षित रूप से काम करता है। मानचित्रों के लिए, हम किसी भी कुंजी-मूल्य जोड़ी (एक लेन -2 वेक्टर के रूप में व्यक्त) की खोज कर सकते हैं:

 (testing "maps"
    (let [coll {1 :two "three" \4}]
      (isnt (contains-elem? coll nil ))
      (isnt (contains-elem? coll [1 :no-way] ))
      (is   (contains-elem? coll [1 :two]))
      (is   (contains-elem? coll ["three" \4])))
    (let [coll {1 nil "three" \4}]
      (isnt (contains-elem? coll [nil 1] ))
      (is   (contains-elem? coll [1 nil] )))
    (let [coll {nil 2 "three" \4}]
      (isnt (contains-elem? coll [1 nil] ))
      (is   (contains-elem? coll [nil 2] ))))

किसी सेट की खोज करना भी सीधा है:

  (testing "sets"
    (let [coll #{1 :two "three" \4}]
      (isnt (contains-elem? coll  :no-way))
      (is   (contains-elem? coll  1))
      (is   (contains-elem? coll  :two))
      (is   (contains-elem? coll  "three"))
      (is   (contains-elem? coll  \4)))

    (let [coll #{:yes nil}]
      (isnt (contains-elem? coll  :no-way))
      (is   (contains-elem? coll  :yes))
      (is   (contains-elem? coll  nil)))))

मानचित्र और सेटों के लिए, contains-key?मानचित्र प्रविष्टि या एक सेट तत्व खोजने के लिए उपयोग करना सरल (और अधिक कुशल) है :

(deftest t-contains-key?
  (is   (contains-key?  {:a 1 :b 2} :a))
  (is   (contains-key?  {:a 1 :b 2} :b))
  (isnt (contains-key?  {:a 1 :b 2} :x))
  (isnt (contains-key?  {:a 1 :b 2} :c))
  (isnt (contains-key?  {:a 1 :b 2}  1))
  (isnt (contains-key?  {:a 1 :b 2}  2))

  (is   (contains-key?  {:a 1 nil   2} nil))
  (isnt (contains-key?  {:a 1 :b  nil} nil))
  (isnt (contains-key?  {:a 1 :b    2} nil))

  (is   (contains-key? #{:a 1 :b 2} :a))
  (is   (contains-key? #{:a 1 :b 2} :b))
  (is   (contains-key? #{:a 1 :b 2}  1))
  (is   (contains-key? #{:a 1 :b 2}  2))
  (isnt (contains-key? #{:a 1 :b 2} :x))
  (isnt (contains-key? #{:a 1 :b 2} :c))

  (is   (contains-key? #{:a 5 nil   "hello"} nil))
  (isnt (contains-key? #{:a 5 :doh! "hello"} nil))

  (throws? (contains-key? [:a 1 :b 2] :a))
  (throws? (contains-key? [:a 1 :b 2]  1)))

और, मानचित्रों के लिए, आप निम्न मानों की खोज भी कर सकते हैं contains-val?:

(deftest t-contains-val?
  (is   (contains-val? {:a 1 :b 2} 1))
  (is   (contains-val? {:a 1 :b 2} 2))
  (isnt (contains-val? {:a 1 :b 2} 0))
  (isnt (contains-val? {:a 1 :b 2} 3))
  (isnt (contains-val? {:a 1 :b 2} :a))
  (isnt (contains-val? {:a 1 :b 2} :b))

  (is   (contains-val? {:a 1 :b nil} nil))
  (isnt (contains-val? {:a 1 nil  2} nil))
  (isnt (contains-val? {:a 1 :b   2} nil))

  (throws? (contains-val?  [:a 1 :b 2] 1))
  (throws? (contains-val? #{:a 1 :b 2} 1)))

जैसा कि परीक्षण में देखा गया है, इनमें से प्रत्येक फ़ंक्शन nilमानों की खोज के लिए सही ढंग से काम करता है ।


0

एक अन्य विकल्प:

((set '(100 101 102)) 101)

Java.util.Collection # को शामिल करें ():

(.contains '(100 101 102) 101)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.