হাস্কেল ব্যবহার করে অ্যারেগুলির প্রয়োজন হয় এমন কাজগুলির সাথে ডিল করার একটি ভাল উপায় কী?


11

প্রায়শই একটি টাস্কের জন্য রিয়েল অ্যারে দরকার হয়। উদাহরণস্বরূপ বেফুঞ্জ বা> <> প্রয়োগ করার জন্য কার্যটি গ্রহণ করুন। আমি Arrayএটির জন্য মডিউলটি ব্যবহার করার চেষ্টা করেছি , তবে এটি সত্যই জটিল as কারণ এটির মতো মনে হচ্ছে আমি অনেক ভার্জোজ কোডিং করছি। কেউ আমাকে কীভাবে এই জাতীয় কোড-গল্ফ কার্যগুলি কম ভার্বোস এবং আরও কার্যকরী সমাধান করতে সহায়তা করতে পারে?


আফাইক, এই সাইটটি কেবল কোড গল্ফের জন্য, সম্পর্কিত প্রশ্নের জন্য নয়। আমি অনুমান করছি যে এটি স্ট্যাকওভারফ্লোতে অন্তর্ভুক্ত।
জেসি মিলিকান

@ জেসি মিলিকান: দয়া করে এই প্রশ্নটি দেখুন এবং প্রশ্নগুলি পড়ুন। এতে বলা হয় না যে, গল্ফ কীভাবে করা যায় সে সম্পর্কে আপনাকে কোনও প্রশ্ন জিজ্ঞাসা করার অনুমতি নেই। এই ধরণের প্রশ্নগুলি এই সাইটের সংজ্ঞা পর্বে "বিষয়বস্তু" প্রশ্নের একটি বড় অংশ ছিল। দয়া করে আপনার ডাউনটোটটি ডাবল-ভাবেন এবং যদি আমি বুঝতে পারি যে আপনি কেন এখানে জিজ্ঞাসা করছেন তা বুঝতে পারলে এটি সরিয়ে দিন।
FUZxxl

হুম, আমার খারাপ ধারণা।
জেসি মিলিকান

@ জেসি মিলিকান: এরার হিউম্যানাম এস্ত্রি।
ফুজজেক্সএল

যদিও এ সম্পর্কে প্রায়শই জিজ্ঞাসিত প্রশ্নাগুলি খুব পরিষ্কার নয়।
জেসি মিলিকান

উত্তর:


5

প্রথমত, আমি ডেটা.ভেক্টরকে দেখার পরামর্শ দিই , কিছু ক্ষেত্রে ডেটা.আরয়ের একটি ভাল বিকল্প ।

Arrayএবং "সর্বাধিক পাথ সন্ধান করা" সম্পর্কে আমার জবাবVector হিসাবে প্রমাণিত কিছু স্মৃতিচারণ মামলার জন্য আদর্শ । তবে কিছু সমস্যা কেবল কার্যকরী শৈলীতে প্রকাশ করা সহজ নয়। উদাহরণস্বরূপ, সমস্যা 28 মধ্যে প্রকল্প ইউলার একটি সর্পিল এর কর্ণ সংখ্যা summing জন্য আহ্বান জানাচ্ছে। অবশ্যই, এই সংখ্যার জন্য সূত্রটি খুঁজে পাওয়া খুব সহজ হওয়া উচিত, তবে সর্পিলটি তৈরি করা আরও চ্যালেঞ্জক।

ডেটা.আরে.এসটি একটি মিউটেটেবল অ্যারে প্রকার সরবরাহ করে। যাইহোক, টাইপ অবস্থা একটি জগাখিচুড়ি: এটা ব্যবহার বর্গ MArray ছাড়া তার পদ্ধতির প্রতি একক এক জমিদার করার runSTArray । সুতরাং, যদি না আপনি কোনও পরিবর্তনীয় অ্যারের ক্রিয়া থেকে অপরিবর্তনযোগ্য অ্যারে ফেরত দেওয়ার পরিকল্পনা না করেন, আপনাকে এক বা একাধিক ধরণের স্বাক্ষর যুক্ত করতে হবে:

import Control.Monad.ST
import Data.Array.ST

foo :: Int -> [Int]
foo n = runST $ do
    a <- newArray (1,n) 123 :: ST s (STArray s Int Int) -- this type signature is required
    sequence [readArray a i | i <- [1..n]]

main = print $ foo 5

তবুও, অ্যালার 28-তে আমার সমাধানটি বেশ সুন্দরভাবে বেরিয়ে এসেছিল এবং আমি ব্যবহার করেছি বলে এ জাতীয় স্বাক্ষরের প্রয়োজন হয় না runSTArray

ডেটা.ম্যাপকে "পরিবর্তনযোগ্য অ্যারে" হিসাবে ব্যবহার করা হচ্ছে

আপনি যদি কোনও মিউটেটেবল অ্যারে অ্যালগরিদম বাস্তবায়ন করতে চান তবে অন্য বিকল্পটি হ'ল ডেটা.ম্যাপ । আপনি যখন একটি অ্যারে ব্যবহার করেন, আপনার ধরণের ইচ্ছে মতো আপনার কোনও ফাংশন থাকে যা অ্যারের একক উপাদানকে পরিবর্তন করে:

writeArray :: Ix i => i -> e -> Array i e -> Array i e

দুর্ভাগ্যক্রমে, এটির জন্য পুরো অ্যারে অনুলিপি করা দরকার, যদি না সম্ভব হয় যখন সম্ভব হয় তা এড়াতে কোনও অনুলিপি কৌশল প্রয়োগ না করে implementation

সুসংবাদটি হ'ল, Data.Mapএর মতো একটি ফাংশন রয়েছে, sertোকান :

insert :: Ord k => k -> a -> Map k a -> Map k a

কারণ Mapঅভ্যন্তরীণভাবে ভারসাম্য বাইনারি গাছ হিসাবে প্রয়োগ করা হয়, insertকেবলমাত্র ও (লগ এন) সময় এবং স্থান নেয় এবং মূল অনুলিপি সংরক্ষণ করে। সুতরাং, Mapকেবলমাত্র কিছুটা দক্ষ "মিউটেবল অ্যারে" সরবরাহ করে না যা কার্যকরী প্রোগ্রামিং মডেলের সাথে সামঞ্জস্যপূর্ণ, তবে এটি যদি আপনি চান তবে আপনাকে "সময়মতো ফিরে যেতে" দেয়।

ডেটা.ম্যাপ ব্যবহার করে অুলার 28 এর একটি সমাধান এখানে রয়েছে:

{-# LANGUAGE BangPatterns #-}

import Data.Map hiding (map)
import Data.List (intercalate, foldl')

data Spiral = Spiral Int (Map (Int,Int) Int)

build :: Int -> [(Int,Int)] -> Map (Int,Int) Int
build size = snd . foldl' move ((start,start,1), empty) where
    start = (size-1) `div` 2
    move ((!x,!y,!n), !m) (dx,dy) = ((x+dx,y+dy,n+1), insert (x,y) n m)

spiral :: Int -> Spiral
spiral size
    | size < 1  = error "spiral: size < 1"
    | otherwise = Spiral size (build size moves) where
        right   = (1,0)
        down    = (0,1)
        left    = (-1,0)
        up      = (0,-1)
        over n  = replicate n up ++ replicate (n+1) right
        under n = replicate n down ++ replicate (n+1) left
        moves   = concat $ take size $ zipWith ($) (cycle [over, under]) [0..]

spiralSize :: Spiral -> Int
spiralSize (Spiral s m) = s

printSpiral :: Spiral -> IO ()
printSpiral (Spiral s m) = do
    let items = [[m ! (i,j) | j <- [0..s-1]] | i <- [0..s-1]]
    mapM_ (putStrLn . intercalate "\t" . map show) items

sumDiagonals :: Spiral -> Int
sumDiagonals (Spiral s m) =
    let total = sum [m ! (i,i) + m ! (s-i-1, i) | i <- [0..s-1]]
     in total-1 -- subtract 1 to undo counting the middle twice

main = print $ sumDiagonals $ spiral 1001

ঠাণ্ডা নিদর্শনগুলি সঞ্চয়ের আইটেমগুলি (কার্সার, সংখ্যা এবং মানচিত্র) একেবারে শেষ অবধি ব্যবহার না করায় স্ট্যাকের ওভারফ্লো প্রতিরোধ করে। বেশিরভাগ কোড গল্ফগুলির জন্য, এই বিধানের প্রয়োজনের জন্য ইনপুট কেসগুলি এত বড় হওয়া উচিত নয়।


9

গ্লিব উত্তর: অ্যারে ব্যবহার করবেন না। তাত্পর্যপূর্ণ উত্তর নয়: আপনার সমস্যাটি পুনর্বিবেচনা করার চেষ্টা করুন যাতে এটির অ্যারে না লাগে।

প্রায়শই, কিছু চিন্তাভাবনা নিয়ে সমস্যা কোনও বিন্যাসের মতো বিন্যাস ছাড়াই করা যায়। উদাহরণস্বরূপ, এখানে অয়লার 28 এর আমার উত্তর:

-- | What is the sum of both diagonals in a 1001 by 1001 spiral?
euler28 = spiralDiagonalSum 1001

spiralDiagonalSum n
    | n < 0 || even n = error "spiralDiagonalSum needs a positive, odd number"
    | otherwise = sum $ scanl (+) 1 $ concatMap (replicate 4) [2,4..n]

এখানে কোডে যা প্রকাশ করা হয় তা হ'ল সংখ্যার ক্রমের ধরণটি আয়তক্ষেত্রাকার সর্পিলের চারপাশে বেড়ে ওঠার সাথে সাথে। আসলে নিজেই সংখ্যার ম্যাট্রিক্স উপস্থাপন করার প্রয়োজন ছিল না।

অ্যারে ছাড়িয়ে চিন্তা করার মূল চাবিকাঠিটি হ'ল সমস্যাটি আসলে কী বোঝায় তা নয়, আপনি কীভাবে এটি র‌্যামের বাইট হিসাবে উপস্থাপন করতে পারেন তা নয়। এটি কেবল অনুশীলনের সাথেই আসে (সম্ভবত আমি কোড-গল্ফকে এতটা কোড করার কারণ হতে পারে!)

আরেকটি উদাহরণ হ'ল আমি কীভাবে সর্বাধিক পাথ কোড-গল্ফ সন্ধান করব। সেখানে ম্যাট্রিক্সের মাধ্যমে তরঙ্গ হিসাবে আংশিক সমাধানগুলি সারি সারি সারি পাশ করার পদ্ধতিটি ভাঁজ অপারেশনের মাধ্যমে সরাসরি প্রকাশ করা হয়। মনে রাখবেন: বেশিরভাগ সিপিইউতে আপনি একবারে অ্যারের সাথে পুরোটা ডিল করতে পারবেন না: সময়ের সাথে সাথে প্রোগ্রামটি পরিচালনা করতে চলেছে। এটি একবারে একবারে পুরো অ্যারের প্রয়োজন নাও হতে পারে।

অবশ্যই কিছু সমস্যা এমনভাবে বলা হয়েছে যে সেগুলি সহজাতভাবে অ্যারে ভিত্তিক। > <>, বেফুঞ্জ, বা ব্রেনফাকের মতো ভাষাগুলির হৃদয় রয়েছে। যাইহোক, এমনকি সেখানে, অ্যারে প্রায়শই সরবরাহ করা যেতে পারে। উদাহরণস্বরূপ, ব্রেনফাককে ব্যাখ্যা করার জন্য আমার সমাধানটি দেখুন , এর শব্দার্থবিজ্ঞানের আসল মূলটি একটি জিপার । এইভাবে ভাবতে শুরু করার জন্য, অ্যাক্সেসের ধরণগুলি এবং সমস্যার অর্থের কাঠামোটির দিকে মনোনিবেশ করুন। প্রায়শই এগুলি পরিবর্তনীয় অ্যারেতে বাধ্য করা হয় না।

যখন সমস্ত কিছু ব্যর্থ হয়, এবং আপনার কোনও অ্যারে ব্যবহার করা দরকার - @ জোয়ের টিপস একটি ভাল শুরু।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.