common-lisp
समानता और अन्य तुलना भविष्यवाणी करती है
खोज…
EQ और EQL के बीच अंतर
EQ
जाँचता है कि क्या दो मानों का मेमोरी का पता समान है: दूसरे शब्दों में, यह जाँचता है कि क्या दो मान वास्तव में एक जैसे हैं , समान वस्तु। इसलिए, इसे पहचान परीक्षण माना जा सकता है, और इसे केवल संरचनाओं पर लागू किया जाना चाहिए: सहमति, सरणियाँ, संरचनाएं, वस्तुएं, आमतौर पर यह देखने के लिए कि क्या आप एक ही वस्तु के साथ वास्तव में काम कर रहे हैं "पहुंच" अलग-अलग रास्तों के माध्यम से, या अन्य के माध्यम से विभिन्न चर।EQL
जाँच करता है कि क्या दो संरचनाएँ एक ही वस्तु (जैसेEQ
) हैं या यदि वे समान संरचना वाले मान हैं (अर्थात, एक ही प्रकार या वर्ण मानों की संख्या के लिए समान संख्यात्मक मान)। चूंकि इसमेंEQ
ऑपरेटर शामिल है और इसका उपयोग गैर-संरचित मूल्यों पर भी किया जा सकता है, यह सबसे महत्वपूर्ण और सबसे अधिक इस्तेमाल किया जाने वाला ऑपरेटर है, और लगभग सभी आदिम कार्यों में समानता की आवश्यकता होती है, जैसे किMEMBER
, इस ऑपरेटर को डिफ़ॉल्ट रूप से उपयोग करता है ।
इसलिए, यह हमेशा सही होता है कि (EQ XY)
का तात्पर्य (EQL XY)
, जबकि (EQL XY)
पकड़ नहीं है।
कुछ उदाहरण दो ऑपरेटरों के बीच अंतर को साफ कर सकते हैं:
(eq 'a 'a)
T ;; => since two s-expressions (QUOTE A) are “internalized” as the same symbol by the reader.
(eq (list 'a) (list 'a))
NIL ;; => here two lists are generated as different objects in memory
(let* ((l1 (list 'a))
(l2 l1))
(eq l1 l2))
T ;; => here there is only one list which is accessed through two different variables
(eq 1 1)
?? ;; it depends on the implementation: it could be either T or NIL if integers are “boxed”
(eq #\a #\a)
?? ;; it depends on the implementation, like for numbers
(eq 2d0 2d0)
?? ;; => dependes on the implementation, but usually is NIL, since numbers in double
;; precision are treated as structures in many implementations
(let ((a1 2d0)
(a2 2d0))
(eq a1 a2))
?? ;; => also in this case the results depends on the implementation
आइए EQL
साथ समान उदाहरणों का प्रयास करें:
(eql 'a 'a)
T ;; => equal because they are the same value, as for EQ
(eql (list 'a) (list 'a))
NIL ;; => different because they different objects in memory, as for EQ
(let* ((l1 (list 'a))
(l2 l1))
(eql l1 l2))
T ;; => as above
(eql 1 1)
T ;; they are the same number, even if integers are “boxed”
(eql #\a #\a)
T ;; they are the same character
(eql 2d0 2d0)
T ;; => they are the same number, even if numbers in double precision are treated as
;; structures in many implementations
(let ((a1 2d0)
(a2 2d0))
(eql a1 a2))
T ;; => as before
(eql 2 2.0)
NIL;; => since the two values are of a different numeric type
उदाहरणों से हम देख सकते हैं कि सभी मानों, संरचित और गैर-संरचित के लिए EQL
ऑपरेटर का उपयोग "समता" के लिए EQL
रूप से जांच करने के लिए क्यों किया जाना चाहिए, और वास्तव में कई विशेषज्ञ सामान्य रूप से EQ
के उपयोग के खिलाफ सलाह क्यों देते हैं।
EQUAL, EQUALP, TREE-EQUAL के साथ संरचनात्मक समानता
ये तीन ऑपरेटर संरचनात्मक तुल्यता को लागू करते हैं, यह है कि क्या वे जांचते हैं कि क्या अलग, जटिल वस्तुओं में बराबर घटक के साथ समान संरचना है।
EQUAL
गैर-संरचित डेटा के लिए EQL
तरह व्यवहार करता है, जबकि कंस (सूचियों और पेड़ों) द्वारा निर्मित संरचनाओं के लिए, और दो विशेष प्रकार के सरणियों, तार और बिट वैक्टर, यह संरचनात्मक समतुल्यता का प्रदर्शन करता है , दो संरचनाओं पर सच लौटाता है जो कि आइसोमोर्फिक है और जिनके प्राथमिक घटक EQUAL
द्वारा EQUAL
से EQUAL
। उदाहरण के लिए:
(equal (list 1 (cons 2 3)) (list 1 (cons 2 (+ 2 1))))
T ;; => since the two arguments are both equal to (1 (2 . 3))
(equal "ABC" "ABC")
T ;; => equality on strings
(equal "Abc" "ABC")
NIL ;; => case sensitive equality on strings
(equal '(1 . "ABC") '(1 . "ABC"))
T ;; => equal since it uses EQL on 1 and 1, and EQUAL on "ABC" and "ABC"
(let* ((a (make-array 3 :initial-contents '(1 2 3)))
(b (make-array 3 :initial-contents '(1 2 3)))
(c a))
(values (equal a b)
(equal a c)))
NIL ;; => the structural equivalence is not used for general arrays
T ;; => a and c are alias for the same object, so it is like EQL
EQUALP
सभी मामलों पर सही है जिसमें EQUAL
सच है, लेकिन यह संरचना और हैश तालिकाओं के लिए (लेकिन वर्ग उदाहरणों के लिए नहीं!) किसी भी प्रकार और आयाम के सरणियों के लिए संरचनात्मक तुल्यता का उपयोग करता है। इसके अलावा, यह स्ट्रिंग्स के लिए केस असंवेदनशील तुल्यता का उपयोग करता है।
(equalp "Abc" "ABC")
T ;; => case insensitive equality on strings
(equalp (make-array 3 :initial-contents '(1 2 3))
(make-array 3 :initial-contents (list 1 2 (+ 2 1))))
T ;; => the structural equivalence is used also for any kind of arrays
(let ((hash1 (make-hash-table))
(hash2 (make-hash-table)))
(setf (gethash 'key hash1) 42)
(setf (gethash 'key hash2) 42)
(print (equalp hash1 hash2))
(setf (gethash 'another-key hash1) 84)
(equalp hash1 hash2))
T ;; => after the first two insertions, hash1 and hash2 have the same keys and values
NIL ;; => after the third insertion, hash1 and hash2 have different keys and values
(progn (defstruct s) (equalp (make-s) (make-s)))
T ;; => the two values are structurally equal
(progn (defclass c () ()) (equalp (make-instance 'c) (make-instance 'c)))
NIL ;; => two structurally equivalent class instances returns NIL, it's up to the user to
;; define an equality method for classes
अंत में, TREE-EQUAL
के माध्यम से निर्मित संरचनाओं के लिए लागू किया जा सकता cons
अगर वे isomorphic कर रहे हैं, की तरह और चेक EQUAL
है, लेकिन चुनाव जो समारोह के लीफ़्स तुलना करने के लिए उपयोग करने के लिए उपयोगकर्ता, यानी गैर विपक्ष (परमाणु) का सामना करना पड़ा करने के लिए छोड़ रहा है, यह किसी भी अन्य डेटा प्रकार का हो सकता है (डिफ़ॉल्ट रूप से, परमाणु पर उपयोग किया जाने वाला परीक्षण EQL
)। उदाहरण के लिए:
(let ((l1 '(1 . ("A" . 2)))
(l2 '(1 . ("A" . 2))))
(tree-equal l1 l2 :test #'eql))
NIL ;; => since (eql "A" "A") gives NIL
(let ((l1 '(1 . ("A" . 2)))
(l2 '(1 . ("A" . 2))))
(tree-equal l1 l2 :test #'equal))
T ;; since (equal "A" "A") gives T
संख्यात्मक मूल्यों पर तुलना ऑपरेटरों
संख्यात्मक मान =
और अन्य संख्यात्मक तुलना ऑपरेटरों ( /=
, <
<=
, >
, >=
) के साथ तुलना कर सकते हैं जो विभिन्न प्रकार की संख्याओं के भौतिक प्रतिनिधित्व में अंतर को अनदेखा करते हैं, और संबंधित गणितीय मूल्यों की तुलना करते हैं। । उदाहरण के लिए:
(= 42 42)
T ;; => both number have the sme numeric type and the same value
(= 1 1.0 1d0)
T ;; => all the tree values represent the number 1, while for instance (eql 1 1d0) => NIL
;; since it returns true only if the operands have the same numeric type
(= 0.0 -0.0)
T ;; => again, the value is the same, while (eql 0.0 -0.0) => NIL
(= 3.0 #c(3.0 0.0))
T ;; => a complex number with 0 imaginary part is equal to a real number
(= 0.33333333 11184811/33554432)
T ;; => since a float number is passed to RATIONAL before comparing it to another number
;; => and (RATIONAL 0.33333333) => 11184811/33554432 in 32-bit IEEE floats architectures
(= 0.33333333 0.33333334)
T ;; => since the result of RATIONAL on both numbers is equal in 32-bit IEEE floats architectures
(= 0.33333333d0 0.33333334d0)
NIL ;; => since the RATIONAL of the two numbers in double precision is different
इन उदाहरणों से, हम यह निष्कर्ष निकाल सकते हैं कि =
वह ऑपरेटर है जो सामान्य रूप से संख्यात्मक मानों के बीच तुलना करने के लिए उपयोग किया जाना चाहिए, जब तक कि हम इस तथ्य पर सख्त नहीं होना चाहते कि दो संख्यात्मक मान केवल समान हैं यदि उनके पास भी समान संख्यात्मक प्रकार हैं, तो किस मामले में EQL
का उपयोग किया जाना चाहिए।
पात्रों और तारों पर तुलना ऑपरेटरों
कॉमन लिस्प में दो पात्रों की तुलना करने के लिए 12 प्रकार के विशिष्ट ऑपरेटर हैं, जिनमें से 6 केस सेंसिटिव हैं और अन्य केस असंवेदनशील हैं। उनके नाम उनके अर्थ को याद रखने में आसान बनाने के लिए एक सरल पैटर्न है:
अक्षर संवेदनशील | असंवेदनशील मामला |
---|---|
CHAR = | CHAR-समान |
CHAR / = | CHAR-नहीं-समान |
CHAR < | CHAR-LESSP |
CHAR <= | CHAR-नहीं-GREATERP |
CHAR> | CHAR-GREATERP |
CHAR> = | CHAR-नहीं-LESSP |
एक ही मामले के दो वर्ण CHAR-CODE
द्वारा प्राप्त संगत कोड के समान क्रम में हैं, जबकि मामले के लिए असंवेदनशील तुलना में दो रेंजों a..z
, A..Z
से लागू किए गए किन्हीं दो वर्णों के बीच सापेक्ष क्रम निर्भर है। । उदाहरण:
(char= #\a #\a)
T ;; => the operands are the same character
(char= #\a #\A)
NIL ;; => case sensitive equality
(CHAR-EQUAL #\a #\A)
T ;; => case insensitive equality
(char> #\b #\a)
T ;; => since in all encodings (CHAR-CODE #\b) is always greater than (CHAR-CODE #\a)
(char-greaterp #\b \#A)
T ;; => since for case insensitive the ordering is such that A=a, B=b, and so on,
;; and furthermore either 9<A or Z<0.
(char> #\b #\A)
?? ;; => the result is implementation dependent
स्ट्रिंग्स के लिए विशिष्ट ऑपरेटर CHAR के बजाय STRING शब्द के साथ STRING=
, STRING-EQUAL
आदि हैं। दो तार बराबर हैं यदि उनके समान वर्ण हैं और संगत वर्ण CHAR=
या CHAR-EQUAL
अनुसार CHAR-EQUAL
यदि परीक्षण संवेदनशील है या नहीं।
तार के बीच आदेश दो तार के पात्रों पर tje lexicographic क्रम है। जब एक ऑर्डरिंग तुलना सफल होती है, तो परिणाम T
नहीं होता है, लेकिन पहले वर्ण का सूचकांक जिसमें दो तार अलग होते हैं (जो कि सत्य के बराबर है, क्योंकि हर गैर-एनआईएल वस्तु आम लिस्प में "सामान्यीकृत बूलियन" है)।
एक महत्वपूर्ण बात यह है कि स्ट्रिंग पर सभी तुलनात्मक ऑपरेटर चार कीवर्ड मापदंडों को स्वीकार करते हैं: start1
, end1
, start2
, end2
, जिसका उपयोग केवल एक या दोनों स्ट्रिंग्स के अंदर वर्णों के एक end2
रन की तुलना को सीमित करने के लिए किया जा सकता है। प्रारंभ किया गया इंडेक्स यदि 0 है, तो इंडेक्स इंडिकेटेड छोड़ा गया है, स्ट्रिंग की लंबाई के बराबर है, और इंडेक्स के साथ कैरेक्टर पर शुरू करने वाले सबस्ट्रिंग पर किए गए तुलना में तुलना :start
इंडेक्स के साथ कैरेक्टर के साथ :start
और समाप्ति :end - 1
शामिल है।
अंत में, ध्यान दें कि एक स्ट्रिंग, यहां तक कि एकल चरित्र के साथ, एक चरित्र की तुलना नहीं की जा सकती है।
उदाहरण:
(string= "foo" "foo")
T ;; => both strings have the same lenght and the characters are `CHAR=` in order
(string= "Foo" "foo")
NIL ;; => case sensitive comparison
(string-equal "Foo" "foo")
T ;; => case insensitive comparison
(string= "foobar" "barfoo" :end1 3 :start2 3)
T ;; => the comparison is perform on substrings
(string< "fooarr" "foobar")
3 ;; => the first string is lexicographically less than the second one and
;; the first character different in the two string has index 3
(string< "foo" "foobar")
3 ;; => the first string is a prefix of the second and the result is its length
एक विशेष मामले के रूप में, स्ट्रिंग तुलना ऑपरेटरों को प्रतीकों पर भी लागू किया जा सकता है, और तुलना SYMBOL-NAME
के SYMBOL-NAME
पर की जाती है। उदाहरण के लिए:
(string= 'a "A")
T ;; since (SYMBOL-NAME 'a) is "A"
(string-equal '|a| 'a)
T ;; since the the symbol names are "a" and "A" respectively
अंतिम नोट के रूप में, EQL
पर EQL
CHAR=
बराबर है; स्ट्रिंग्स पर EQUAL
STRING=
बराबर है, जबकि स्ट्रिंग्स पर EQUALP
STRING-EQUAL
।
Overwiew
आम लिस्प में मूल्यों की तुलना करने के लिए कई अलग-अलग विधेय हैं। उन्हें निम्नलिखित श्रेणियों में वर्गीकृत किया जा सकता है:
- सामान्य समानता ऑपरेटर: EQ, EQL, EQUAL, EQUALP। उनका उपयोग किसी भी प्रकार के मूल्यों के लिए किया जा सकता है और हमेशा एक बूलियन मान T या NIL लौटाता है।
- विशिष्ट समानता ऑपरेटर टाइप करें: = और = संख्याओं के लिए, वर्णों के लिए CHAR = CHAR = CHAR-EQUAL CHAR-NOT-EQUAL, स्ट्रिंग्स के लिए STRING = STRING = EQUAL STRING-NOT-EQUAL, सहमति के लिए TREE-EQUAL।
- संख्यात्मक मानों के लिए तुलना ऑपरेटर: <, <=>,> = =। वे किसी भी प्रकार की संख्या पर लागू हो सकते हैं और वास्तविक प्रकार से स्वतंत्र रूप से संख्या के गणितीय मूल्य की तुलना कर सकते हैं।
- वर्णों के लिए तुलना ऑपरेटर, जैसे CHAR <, CHAR-LESSP, आदि, जो वर्णों की तुलना किसी मामले में संवेदनशील तरीके से करते हैं या एक मामले में असंवेदनशील तरीके से, एक आदेश के अनुसार कार्यान्वयन के अनुसार जो प्राकृतिक वर्णमाला क्रम को संरक्षित करता है।
- स्ट्रिंग्स के लिए तुलना ऑपरेटर, जैसे STRING <, STRING-LESSP, आदि, जो लेक्सिक रूप से स्ट्रिंग्स की तुलना करते हैं, या तो केस संवेदी तरीके से या केस असंवेदनशील तरीके से, चरित्र तुलना ऑपरेटरों का उपयोग करके।