۹ - ۱۱زیپ کردن لیست‌ها

زیپ کردن ِ لیست‌ها راهی برای ترکیب ِ مقادیرِ چند لیست، به داخلِ یک لیست‌ه. تابعِ ‏‎zipWith‎‏ تابع جامع‌تری از ‏‎zip‎‏ هست که اجازه میده از هر تابعِ ترکیب‌کننده ای (م. بجای توپل‌ساز) بین دو لیست استفاده کنین.

اول ‏‎zip‎‏ رو ببینیم:

Prelude> :t zip
zip :: [a] -> [b] -> [(a,b)]

Prelude> zip [1, 2, 3] [4, 5, 6]
[(1,4),(2,5),(3,6)]

یکی از نکاتِ ‏‎zip‎‏ اینه که به محض تموم شدنِ یکی از لیست‌ها متوقف میشه:

Prelude> zip [1, 2] [4, 5, 6]
[(1,4),(2,5)]

Prelude> zip [1, 2, 3] [4]
[(1,4)]

پس اگه یکی‌شون خالی باشه، جواب هم لیست خالی میشه:

Prelude> zip [] [1..1000000000000000000]
[]

تا جایی پیش میره که کوتاه‌ترین لیست تموم شه:

Prelude> zip ['a'] [1..1000000000000000000]
[('a',1)]
Prelude> zip [1..100] ['a'..'c']
[(1,'a'),(2,'b'),(3,'c')]

با ‏‎unzip‎‏ میشه لیست‌ها رو قبل از زیپ شدن‌شون بدست آورد:

Prelude> zip [1, 2, 3] [4, 5, 6]
[(1,4),(2,5),(3,6)]
Prelude> unzip $ zip [1, 2, 3] [4, 5, 6]
([1,2,3],[4,5,6])
Prelude> fst $ unzip $ zip [1, 2, 3] [4, 5, 6]
[1,2,3]
Prelude> snd $ unzip $ zip [1, 2, 3] [4, 5, 6]
[4,5,6]

حواستون باشه که در این پروسه، اطلاعات ممکنه از بین بره (چون ‏‎zip‎‏ تا کوتاه‌ترین لیست پیش میره):

Prelude> snd $ unzip $ zip [1, 2] [4, 5, 6]
[4,5]

با ‏‎zipWith‎‏ میشه یک تابع رو به مقادیرِ دو تا لیست به توازی اعمال کرد:

zipWith :: (a -> b -> c)
--              [1]
        -> [a] -> [b] -> [c]
--         [2]    [3]    [4]

۱.

یه تابع با دو آرگومان. به انطباق تایپ‌ها در این تابع، با تایپِ لیست‌ها دقت کنین.

۲.

اولین لیستِ ورودی.

۳.

دومین لیستِ ورودی.

۴.

لیست خروجیِ حاصل از اعمال ِ تابع به مقادیر لیست‌های ورودی.

چندتا مثال از ‏‎zipWith‎‏:

Prelude> zipWith (+) [1, 2, 3] [10, 11, 12]
[11,13,15]

Prelude> zipWith (*) [1, 2, 3] [10, 11, 12]
[10,22,36]

Prelude> zipWith (==) ['a'..'f'] ['a'..'m']
[True,True,True,True,True,True]

Prelude> let xs = [10, 5, 34, 9]
Prelude> let xs' = [6, 8, 12, 7]
Prelude> zipWith max xs xs'
[10,8,34,9]

تمرین‌های زیپ

۱.

تابع ‏‎zip‎‏ ِ خودتون رو تعریف کنین و مطمئن شین که عینِ تابع اصلی کار می‌کنه:

zip :: [a] -> [b] -> [(a,b)]
zip = undefined

۲.

همین کار رو با ‏‎zipWith‎‏ هم انجام بدین:

zipWith :: (a -> b -> c) 
        -> [a] -> [b] -> [c] 
zipWith = undefined

۳.

تابع ‏‎zip‎‏ ِتون رو با ‏‎zipWith‎‏ ای که تعریف کردین بازنویسی کنین.