2014-01-25 5 views
12

Я ищу функцию в haskell, чтобы закрепить два списка, которые могут различаться по длине.
Все функции zip, которые я могу найти, просто отбрасывают все значения списков, которые больше, чем другие.
Почтовый индекс со значением по умолчанию вместо значений сброса?

Например: В моем упражнении у меня есть два примера.
Если первый из них короче второго, я должен заполнить его с помощью 0. В противном случае я должен использовать 1.
Мне не разрешено использовать рекурсию. Мне просто нужно использовать функции более высокого порядка.

Есть ли какая-либо функция, которую я могу использовать?
Я до сих пор не нашел решения.

ответ

6

Вы можете добавить список inifinte 0 или 1 для каждого списка, а затем взять нужный номер из результатов архивный списка:

zipWithDefault :: a -> b -> [a] -> [b] -> [(a,b)] 
zipWithDefault da db la lb = let len = max (length la) (length lb) 
           la' = la ++ (repeat da) 
           lb' = lb ++ (repeat db) 
          in take len $ zip la' lb' 
+6

Не работает с бесконечными списками. – augustss

+0

@ Lee: Извините, мне плохо, да. Он разбивается на бесконечные списки, хотя (даже если он бесконечен), но об этом уже упоминалось. Мой ответ ниже работает с бесконечными и конечными списками. – Clinton

1

Как вы сами сказали, стандартная zip :: [a] -> [b] -> [(a, b)] капли элементы из более длинный список. Чтобы внести поправки в этот факт, вы можете изменить свой ввод до, указав его zip. Сначала вам нужно будет выяснить, какой список является более коротким (скорее всего, используя length). НАПРИМЕР,

zip' x xs y ys | length xs <= length ys = ... 
       | otherwise    = ... 

где x значение по умолчанию для короткого xs и y значения по умолчанию для короче ys.

Затем вы удлиняете более короткий список с требуемыми элементами по умолчанию (достаточно для учета дополнительных элементов другого списка). При этом аккуратный трюк без необходимости знать длину более длинного списка - это использовать функцию repeat :: a -> [a], которая бесконечно повторяет свой аргумент.

zip' x xs y ys | length xs <= length ys = zip {-do something with xs-} ys 
       | otherwise    = zip xs {-do something with ys-} 
+2

Не работает с бесконечными списками. – augustss

+0

@augustss: Верно. Я должен был упомянуть об этом в своем посте. – chris

0

Вам не нужно сравнивать длины списков. Постарайтесь подумать о своей zip-функции как функции, принимающей только один аргумент xs и возвращающей функцию, которая примет ys и выполнит требуемый почтовый индекс. Затем попробуйте написать функцию recursive, которая повторяется только на xs, следующим образом.

type Result = [Int] -> [(Int,Int)] 
myZip :: [Int] -> Result 
myZip []  = map (\y -> (0,y)) -- :: Result 
myZip (x:xs) = f x (myZip xs) -- :: Result 
    where f x k = ???    -- :: Result 

Как только вы нашли f, обратите внимание, что вы можете превратить рекурсию выше в складку!

33

Существует определенная структура этой проблемы, и вот она приходит. Я буду использовать этот материал:

import Control.Applicative 
import Data.Traversable 
import Data.List 

Прежде всего, списки-с-дополнения являются полезной концепцией, так что давайте иметь тип для них.

data Padme m = (:-) {padded :: [m], padder :: m} deriving (Show, Eq) 

Далее, я помню, что truncating- zip операция приводит к появлению Applicative, например, в библиотеке, как newtype ZipList (популярный пример из не- Monad). Applicative ZipList соответствует украшению моноида, заданному бесконечностью и минимумом.Padme имеет аналогичную структуру, за исключением того, что ее основной моноид - это положительные числа (с бесконечностью), используя один и максимум.

instance Applicative Padme where 
    pure = ([] :-) 
    (fs :- f) <*> (ss :- s) = zapp fs ss :- f s where 
    zapp []  ss  = map f ss 
    zapp fs  []  = map ($ s) fs 
    zapp (f : fs) (s : ss) = f s : zapp fs ss 

Я вынужден произнести обычное колдовство для создания по умолчанию Functor экземпляра.

instance Functor Padme where fmap = (<*>) . pure 

Таким образом, мы можем отложить прочь! Например, функция, которая берет оборванный список строк и заполняет их пробелами, становится одним лайнером.

deggar :: [String] -> [String] 
deggar = transpose . padded . traverse (:- ' ') 

См.?

*Padme> deggar ["om", "mane", "padme", "hum"] 
["om ","mane ","padme","hum "] 
4

Это должно сделать трюк:

import Data.Maybe (fromMaybe) 

myZip dx dy xl yl = 
    map (\(x,y) -> (fromMaybe dx x, fromMaybe dy y)) $ 
    takeWhile (/= (Nothing, Nothing)) $ 
    zip ((map Just xl) ++ (repeat Nothing)) ((map Just yl) ++ (repeat Nothing)) 

main = print $ myZip 0 1 [1..10] [42,43,44] 

В принципе, добавить бесконечный список Nothing до конца обоих списков, то сжатие, и падение результатов, когда оба Nothing. Затем замените Nothing s на соответствующее значение по умолчанию, отбросив ненужное значение Just s, пока вы на нем.

0

Вот еще одно решение, которое делает работу на бесконечных списках и является простым обновлением почтовых функций Prelude в:

zipDefault :: a -> b -> [a] -> [b] -> [(a,b)] 
zipDefault _da _db []  []  = [] 
zipDefault da db (a:as) []  = (a,db) : zipDefault da db as [] 
zipDefault da db []  (b:bs) = (da,b) : zipDefault da db [] bs 
zipDefault da db (a:as) (b:bs) = (a,b) : zipDefault da db as bs 

и

zipDefaultWith :: a -> b -> (a->b->c) -> [a] -> [b] -> [c] 
zipDefaultWith _da _db _f []  []  = [] 
zipDefaultWith da db f (a:as) []  = f a db : zipDefaultWith da db f as [] 
zipDefaultWith da db f []  (b:bs) = f da b : zipDefaultWith da db f [] bs 
zipDefaultWith da db f (a:as) (b:bs) = f a b : zipDefaultWith da db f as bs 

@pigworker, спасибо за ваше информативное решение!

Смежные вопросы