मैं एक सूची से nth तत्व कैसे प्राप्त कर सकता हूं?


97

मैं इस सी कोड के अनुरूप, हास्केल में सूचकांक द्वारा एक सूची का उपयोग कैसे कर सकता हूं?

int a[] = { 34, 45, 56 };
return a[1];

जवाबों:


154

देखो यहाँ , इस्तेमाल किया ऑपरेटर है !!

Ie [1,2,3]!!1आपको देता है 2, क्योंकि सूची 0-अनुक्रमित हैं।


86
व्यक्तिगत रूप से मैं समझ नहीं पा रहा हूं कि एक ए-इंडेक्स एक्सेसर जो शायद एक प्रकार को वापस नहीं करता है, मुहावरेदार हास्केल के रूप में स्वीकार्य है। [1,2,3]!!6आपको एक रनटाइम त्रुटि देगा। यह बहुत आसानी से बचा जा सकता है अगर !!टाइप होता [a] -> Int -> Maybe a। हमारे पास हास्केल का बहुत ही कारण इस तरह की रनटाइम त्रुटियों से बचना है!
दुनियासी

9
यह एक व्यापार है। उन्होंने जो प्रतीक चुना वह संभवतः सबसे खतरनाक प्रतीक था जो उनके पास हो सकता है। इसलिए मुझे लगता है कि यह विचार इसे किनारे के मामलों के लिए अनुमति देने के लिए था, लेकिन इसे गैर-मुहावरेदार के रूप में खड़ा करें।
cdosborn

3
itemOf :: Int -> [a] -> Maybe a; x `itemOf` xs = let xslen = length xs in if ((abs x) > xslen) then Nothing else Just (xs !! (x `mod` xslen))। ध्यान दें, यह अनन्त सूची में विनाशकारी रूप से विफल हो जाएगा।
djvs

2
!!एक आंशिक और इस प्रकार असुरक्षित कार्य है। नीचे टिप्पणी पर एक नज़र डालें और lens stackoverflow.com/a/23627631/2574719
goetzc

90

मैं यह नहीं कह रहा हूं कि आपके प्रश्न या दिए गए उत्तर में कुछ भी गलत है, लेकिन शायद आप उस अद्भुत टूल के बारे में जानना चाहेंगे जो भविष्य में खुद को बचाने के लिए Hoogle है: Hoogle के साथ, आप मानक लाइब्रेरी फ़ंक्शंस की खोज कर सकते हैं वह किसी दिए गए हस्ताक्षर से मेल खाता है। इसलिए, !!अपने मामले में कुछ भी नहीं जानने के बाद , आप "कुछ ऐसी चीज़ों की खोज कर सकते हैं जो व्हाट्सएप की Intएक सूची लेती है और एक भी रिटर्न देता है"

Int -> [a] -> a

लो और निहारना , !!पहले परिणाम के रूप में (हालांकि प्रकार के हस्ताक्षर में वास्तव में दो तर्क हैं जो हमने खोजा था उसकी तुलना में उल्टा है)। नीट, हुह?

इसके अलावा, यदि आपका कोड अनुक्रमणिका पर निर्भर करता है (सूची के सामने से उपभोग करने के बजाय), सूची वास्तव में उचित डेटा संरचना नहीं हो सकती है। O (1) अनुक्रमणिका-आधारित पहुँच के लिए अधिक कुशल विकल्प हैं, जैसे सरणियाँ या वैक्टर


4
Hoogle बिल्कुल शानदार है। हर हास्केल प्रोग्रामर को इसे जानना चाहिए। Hayoo ( holumbus.fh-wedel.de/hayoo/hayoo.html ) नामक एक विकल्प है । यह आपके प्रकार के अनुसार खोज करता है, लेकिन Hoogle की तरह चतुर नहीं लगता है।
मुसीक

61

उपयोग का एक विकल्प (!!)का उपयोग है लेंस पैकेज और उसके elementसमारोह और संबद्ध ऑपरेटरों। लेंस के ऊपर और सूचियों से परे संरचनाओं और नेस्टेड संरचनाओं की एक विस्तृत विविधता तक पहुँचने के लिए एक समान अंतरफलक प्रदान करता है। नीचे मैं उदाहरण प्रदान करने पर ध्यान केंद्रित करूंगा और लेंस पैकेज के पीछे दोनों प्रकार के हस्ताक्षर और सिद्धांत पर चमक दूंगा । यदि आप सिद्धांत के बारे में अधिक जानना चाहते हैं तो शुरू करने के लिए एक अच्छी जगह है गिथब रेपो

पहुँच सूची और अन्य डेटाटाइप्स

लेंस पैकेज तक पहुंच प्राप्त करना

कमांड लाइन पर:

$ cabal install lens
$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
> import Control.Lens


पहुंच सूची

इन्फिक्स ऑपरेटर के साथ एक सूची का उपयोग करने के लिए

> [1,2,3,4,5] ^? element 2  -- 0 based indexing
Just 3

इसके विपरीत (!!)एक तत्व को सीमा से बाहर पहुंचने पर अपवाद नहीं फेंकेगा और Nothingइसके बजाय वापस आ जाएगा। यह अक्सर की तरह आंशिक कार्यों से बचने के लिए सलाह देते हैं है (!!)या headके बाद से वे और अधिक कोने मामलों है और अधिक एक रन समय त्रुटि का कारण होने की संभावना है। आप इस विकी पृष्ठ पर आंशिक कार्यों से बचने के बारे में थोड़ा और पढ़ सकते हैं ।

> [1,2,3] !! 9
*** Exception: Prelude.(!!): index too large

> [1,2,3] ^? element 9
Nothing

आप लेंस तकनीक को एक आंशिक फ़ंक्शन होने के लिए बाध्य कर सकते हैं और (^?!)ऑपरेटर के बजाय ऑपरेटर का उपयोग करके सीमा से बाहर होने पर एक अपवाद फेंक सकते हैं (^?)

> [1,2,3] ^?! element 1
2
> [1,2,3] ^?! element 9
*** Exception: (^?!): empty Fold


सूचियों के अलावा अन्य प्रकार के साथ काम करना

यह सिर्फ सूचियों तक ही सीमित नहीं है। उदाहरण के लिए एक ही तकनीक मानक कंटेनरों के पैकेज से पेड़ों पर काम करती है ।

 > import Data.Tree
 > :{
 let
  tree = Node 1 [
       Node 2 [Node 4[], Node 5 []]
     , Node 3 [Node 6 [], Node 7 []]
     ]
 :}
> putStrLn . drawTree . fmap show $tree
1
|
+- 2
|  |
|  +- 4
|  |
|  `- 5
|
`- 3
   |
   +- 6
   |
   `- 7

अब हम पहले-पहले क्रम में पेड़ के तत्वों तक पहुँच सकते हैं:

> tree ^? element 0
Just 1
> tree ^? element 1
Just 2
> tree ^? element 2
Just 4
> tree ^? element 3
Just 5
> tree ^? element 4
Just 3
> tree ^? element 5
Just 6
> tree ^? element 6
Just 7

हम कंटेनर पैकेज से अनुक्रमों तक भी पहुंच सकते हैं :

> import qualified Data.Sequence as Seq
> Seq.fromList [1,2,3,4] ^? element 3
Just 4

हम वेक्टर पैकेज से मानक int अनुक्रमित सरणियों का उपयोग कर सकते हैं , मानक पाठ पैकेज से पाठ , मानक bytestring पैकेज और कई अन्य मानक डेटा संरचनाओं को बाइटस्ट्रेस्ट करते हैं। एक्सेस के इस मानक तरीके को आपकी व्यक्तिगत डेटा संरचनाओं तक बढ़ाया जा सकता है, जिससे उन्हें टाइपकास्ट टावर्सबल का एक उदाहरण बना दिया जा सकता है , उदाहरण के लिए Lens प्रलेखन में ट्रेवर्सेबल्स की लंबी सूची देखें


नेस्टेड संरचनाएँ

नेस्टेड संरचनाओं में नीचे खोदना लेंस हैकेज के साथ सरल है । उदाहरण के लिए सूची की सूची में एक तत्व तक पहुँचने के लिए:

> [[1,2,3],[4,5,6]] ^? element 0 . element 1
Just 2
> [[1,2,3],[4,5,6]] ^? element 1 . element 2
Just 6

यह संरचना तब भी काम करती है जब नेस्टेड डेटा संरचनाएं विभिन्न प्रकार की होती हैं। इसलिए उदाहरण के लिए अगर मेरे पास पेड़ों की सूची थी:

> :{
 let
  tree = Node 1 [
       Node 2 []
     , Node 3 []
     ]
 :}
> putStrLn . drawTree . fmap show $ tree
1
|
+- 2
|
`- 3
> :{
 let 
  listOfTrees = [ tree
      , fmap (*2) tree -- All tree elements times 2
      , fmap (*3) tree -- All tree elements times 3
      ]            
 :}

> listOfTrees ^? element 1 . element 0
Just 2
> listOfTrees ^? element 1 . element 1
Just 4

जब तक वे Traversableआवश्यकता को पूरा करते हैं , तब तक आप मनमाने प्रकार से गहराई से घोंसला बना सकते हैं। इसलिए पाठ के दृश्यों के पेड़ों की सूची तक पहुंचना कोई पसीना नहीं है।


N n तत्व को बदलना

कई भाषाओं में एक सामान्य ऑपरेशन एक सरणी में अनुक्रमित स्थिति को असाइन करना है। अजगर में आप हो सकते हैं:

>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]

लेंस पैकेज के साथ इस कार्यक्षमता देता है (.~)ऑपरेटर। हालांकि अजगर के विपरीत मूल सूची को उत्परिवर्तित नहीं किया जाता है, बल्कि एक नई सूची लौटा दी जाती है।

> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]

element 3 .~ 9सिर्फ एक फ़ंक्शन और (&)ऑपरेटर है, लेंस पैकेज का हिस्सा है , बस रिवर्स फ़ंक्शन एप्लिकेशन है। यहां यह अधिक सामान्य फ़ंक्शन एप्लिकेशन के साथ है।

> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]

असाइनमेंट फिर से Traversableएस के मनमाने ढंग से घोंसले के शिकार के साथ पूरी तरह से ठीक काम करता है ।

> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]

3
क्या मुझे Data.Traversableपुनः निर्यात करने के बजाय लिंक करने का सुझाव देना चाहिए lens?
डेफ़र

@dfeuer - मैंने आधार में Data.Traversable का लिंक जोड़ा है। मैंने पुराने लिंक को भी रखा और बताया कि लेंस प्रलेखन में उदाहरण ट्रेवरबल्स की लंबी सूची थी। सलाह के लिये धन्यवाद।

11

सीधे जवाब पहले से ही दिया गया था: उपयोग करें !!

हालाँकि, newbies अक्सर इस ऑपरेटर को अधिक इस्तेमाल करते हैं, जो हास्केल में महंगा है (क्योंकि आप एकल लिंक्ड सूची पर काम करते हैं, एरे पर नहीं)। इससे बचने के लिए कई उपयोगी तकनीकें हैं, सबसे आसान है जिप का इस्तेमाल। यदि आप लिखते हैं zip ["foo","bar","baz"] [0..], तो आपको एक जोड़ी में प्रत्येक तत्व के लिए "संलग्न" सूचकांकों के साथ एक नई सूची मिलती है: [("foo",0),("bar",1),("baz",2)]जो अक्सर आपकी आवश्यकता होती है।


2
आपको वहां अपने प्रकारों के बारे में सावधान रहने की भी आवश्यकता है। ज्यादातर समय आप तेजी मशीन मशीन के बजाय धीमी सूचकांकों के होने के साथ समाप्त नहीं करना चाहते हैं। इस बात पर निर्भर करता है कि आपका कार्य वास्तव में क्या करता है और आपकी टाइपिंग कितनी स्पष्ट है, हास्केल [इंट] के बजाय [0 ..] के प्रकार [पूर्णांक] का अनुमान लगा सकता है।
क्रिसडब

4

आप उपयोग कर सकते हैं !!, लेकिन यदि आप इसे पुनरावर्ती रूप से करना चाहते हैं तो नीचे यह करने का एक तरीका है:

dataAt :: Int -> [a] -> a
dataAt _ [] = error "Empty List!"
dataAt y (x:xs)  | y <= 0 = x
                 | otherwise = dataAt (y-1) xs

4

हास्केल की मानक सूची डेटा प्रकार forall t. [t] कार्यान्वयन में एक कैनोनिकल सी लिंक्ड सूची से मिलती जुलती है, और इसके अनिवार्य गुण साझा करती है। लिंक की गई सूची सरणियों से बहुत अलग हैं। सबसे विशेष रूप से, एक O (1) निरंतर-समय ऑपरेशन के बजाय, अनुक्रमणिका द्वारा पहुंच O (n) रैखिक है।

यदि आपको लगातार यादृच्छिक पहुंच की आवश्यकता होती है, तो Data.Arrayमानक पर विचार करें ।

!!एक असुरक्षित आंशिक रूप से परिभाषित फ़ंक्शन है, जो आउट-ऑफ-द-रेंज सूचकांकों के लिए एक दुर्घटना को भड़काता है। ध्यान रखें कि मानक पुस्तकालय कुछ इस तरह के आंशिक कार्य (शामिल हो head, last, आदि)। सुरक्षा के लिए, एक विकल्प प्रकार Maybe, या Safeमॉड्यूल का उपयोग करें।

एक यथोचित कुशल, मजबूत कुल का उदाहरण (सूचकांकों के लिए index 0) अनुक्रमण समारोह:

data Maybe a = Nothing | Just a

lookup :: Int -> [a] -> Maybe a
lookup _ []       = Nothing
lookup 0 (x : _)  = Just x
lookup i (_ : xs) = lookup (i - 1) xs

लिंक की गई सूचियों के साथ काम करना, अक्सर अध्यादेश सुविधाजनक होते हैं:

nth :: Int -> [a] -> Maybe a
nth _ []       = Nothing
nth 1 (x : _)  = Just x
nth n (_ : xs) = nth (n - 1) xs

ये कार्य क्रमशः नकारात्मक और असंयमित इनट्स के लिए हमेशा के लिए पुन: उत्पन्न होते हैं।
बजरतूर थोरलासियस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.