2013-12-08 8 views
5

मैं संख्याओं की एक सूची देने वाले एक फ़ंक्शन को लिखने की कोशिश कर रहा हूं, एक सूची देता है जहां अंतिम तत्व से शुरू होने पर प्रत्येक 2 नंबर को मूल्य में दोगुना कर दिया जाता है। तो यदि सूची तत्व 1..n हैं, n-th को छोड़ दिया जा रहा है, (एन -1) - यह मूल्य में दोगुनी हो जायेगा, (एन -2) - यह छोड़ा जा रहा है के रूप में है,हास्केल - एक सुरुचिपूर्ण तरीके से रिवर्स ऑर्डर में सूची तत्वों को फिर से कैसे चालू करें?

तो यहाँ आदि मैं इसे कैसे हल किया है:

MyFunc :: [Integer] -> [Integer] 
MyFunc xs = reverse (MyFuncHelper (reverse xs)) 

MyFuncHelper :: [Integer] -> [Integer] 
MyFuncHelper []  = [] 
MyFuncHelper (x:[]) = [x] 
MyFuncHelper (x:y:zs) = [x,y*2] ++ MyFuncHelper zs 

और यह काम करता है:

MyFunc [1,1,1,1] = [2,1,2,1] 
MyFunc [1,1,1] = [1,2,1] 

हालांकि, मैं मदद नहीं कर सकता लेकिन लगता है कि वहाँ एक सरल हो गया है सूची को वापस करने, इसे संसाधित करने और फिर इसे फिर से उलट करने से समाधान। क्या मैं बस सूची को पीछे की ओर ले सकता हूं? यदि हां, तो कैसे?

+2

आप तत्वों भरोसा कर सकते हैं और फिर या तो हर विषम क्रमांकित या हर सम-संख्यांकित तत्व दोगुना। –

उत्तर

9

lens पुस्तकालय से under reversed f xs मुहावरा उलटे क्रम में XS के लिए च लागू होंगे:

under reversed (take 5) [1..100] => [96,97,98,99,100] 
+5

ध्यान दें कि 'ओवर उलट एफ एक्सएस' एक ही परिणाम देता है, और 'ओवर' एक अधिक सामान्यतः इस्तेमाल किया जाने वाला लेंस संयोजक है। –

+0

यह निश्चित रूप से समस्या को हल करने के सबसे संक्षिप्त तरीके की तरह दिखता है। यह एक शर्म की बात है कि यहां इस्तेमाल की गई विधि प्रीलूड में शामिल नहीं है। – Zaroth

3

जब आप अंत से सूची पर कार्रवाई करने के, आम तौर पर foldr काम करता है बहुत अच्छी तरह से की जरूरत है।

doubleOdd :: Num a => [a] -> [a] 
doubleOdd = fst . foldr multiplyCond ([], False) 
    where multiplyCond x (rest, flag) = ((if flag then (x * 2) else x) : rest, not flag) 

multiplyCond समारोह एक झंडा और संचायक सूची के साथ एक टपल लेता है: यहाँ पूरी सूची दो बार पीछे के बिना आप के लिए एक समाधान है। यह ध्वज ट्रैक करने के लिए ध्वज लगातार चालू और बंद हो जाता है कि हमें तत्व को गुणा करना चाहिए या नहीं। जमाकर्ता सूची केवल परिणामी संख्याओं को इकट्ठा करती है। यह समाधान इतना संक्षिप्त नहीं हो सकता है, लेकिन अतिरिक्त काम से बचाता है और कुछ भी उपयोग नहीं करता है लेकिन कार्यों को हल करता है।

+0

इस फ़ंक्शन में सूची के पहले तत्व का उत्पादन करने के लिए, 'फोल्ड' को सूची के अंत तक पूरी तरह से रिकर्स करना होगा और प्रत्येक जोड़े के दूसरे (बूलियन) तत्व को मजबूर करना होगा। तो मुझे संदेह है कि यह मूल सूची को उलट करने से बेहतर है। –

+0

@LuisCasillas सूची के अंत में जाना अनिवार्य है क्योंकि अंतिम आइटम इससे पहले सभी वस्तुओं को देखे बिना पहुंच योग्य नहीं है। हालांकि, परिणामस्वरूप सूची को पहले से पुनर्प्राप्त तत्वों से तुरंत उत्पादित किया जाता है, बिना दूसरे रिवर्सिंग ऑपरेशन के। शायद दो रिवर्सल आलस्य के साथ एक ही परिणाम प्राप्त होता है, लेकिन मुझे इसके बारे में पूरी तरह से यकीन नहीं है। – Malcolm

1
myFunc = reverse 
     . map (\(b,x) -> if b then x*2 else x) 
     . zip (cycle [False,True]) 
     . reverse 

लेकिन यह बेहतर नहीं है। आपका कार्यान्वयन पर्याप्त रूप से सुरुचिपूर्ण है।

+5

आप इसे 'myFunc = रिवर्स' पर कोड-गोल्फ कर सकते हैं। ज़िप (*) (चक्र [1, 2])। reverse'' – bisserlis

0

सूची को पीछे हटाना सबसे आसान तरीका सूची को पीछे हटाना है। मुझे नहीं लगता कि आप वास्तव में उससे बेहतर कर सकते हैं; मुझे संदेह है कि अगर आपको अंत खोजने के लिए पूरी सूची को पार करना होगा, और याद रखें कि बैक अप कैसे प्राप्त करें, तो आप इसे भी उलट सकते हैं। यदि यह एक बड़ा सौदा है, तो शायद आपको सूचियों के बजाय कुछ अन्य डेटा संरचना का उपयोग करना चाहिए- Vector या Seq अच्छे विकल्प हो सकते हैं।

  1. उपयोग:

    import Control.Monad.State 
    import Data.Traversable (Traversable, traverse) 
    
    toggle :: (Bool -> a -> b) -> a -> State Bool b 
    toggle f a = 
        do active <- get 
         put (not active) 
         return (f active a) 
    
    doubleEvens :: (Num a, Traversable t) => t a -> t a 
    doubleEvens xs = evalState (traverse (toggle step) xs) False 
        where step True x = 2*x 
          step False x = x 
    
    yourFunc :: Num a => [a] -> [a] 
    yourFunc = reverse . doubleEvens 
    

    या अगर हम थोड़ा Foldable और Traversable साथ पागल हो, हम इस कोशिश कर सकते हैं:

    एक और तरीका है अपने सहायक समारोह लिखने के लिए उपयोग करने के लिए Traversable है Foldable के foldl इसके किसी भी उदाहरण से रिवर्स ऑर्डर सूची निकालने के लिए। कुछ प्रकार के लिए यह एक सूची को उलट करने से अधिक कुशल होगा।

  2. फिर हम traverse और State का उपयोग मूल संरचना के प्रत्येक तत्व को उल्टा क्रम में अपने समकक्ष को मैप करने के लिए कर सकते हैं।

यहाँ यह कैसे करना है:

import Control.Monad.State 
import Data.Foldable (Foldable) 
import qualified Data.Foldable as F 
import Data.Traversable (Traversable, traverse) 
import Data.Map (Map) 
import qualified Data.Map as Map 


toReversedList :: Foldable t => t a -> [a] 
toReversedList = F.foldl (flip (:)) [] 

reverse' :: Traversable t => t a -> t a 
reverse' ta = evalState (traverse step ta) (toReversedList ta) 
    where step _ = do (h:t) <- get 
         put t 
         return h 

yourFunc' :: (Traversable t, Num a) => t a -> t a 
yourFunc' = reverse' . doubleEvens 

-- >>> yourFunc' $ Map.fromList [(1, 1), (2, 1), (3, 1), (4, 1)] 
-- fromList [(1,2),(2,1),(3,2),(4,1)] 

-- >>> yourFunc' $ Map.fromList [(1, 1), (2, 1), (3, 1)] 
-- fromList [(1,1),(2,2),(3,1)] 

शायद यह करने के लिए एक बेहतर तरीका है, हालांकि है ...

0

func xs = zipWith (*) xs $ reverse . (take $ length xs) $ cycle [1,2]

संबंधित मुद्दे