首页 文章

使用默认值而不是丢弃值来压缩?

提问于
浏览
14

我正在寻找haskell中的函数来压缩两个长度可能不同的列表 .
我可以找到的所有zip函数只删除比另一个更长的列表的所有值 .

例如:在我的练习中,我有两个示例列表 .
如果第一个比第二个短,我必须使用0 's. Otherwise I have to use 1' s填充 .
我不允许使用任何递归 . 我只需要使用更高阶的函数 .

我可以使用任何功能吗?
到目前为止我真的找不到任何解决方案 .

7 回答

  • 6

    您可以在每个列表中附加0或1的inifinte列表,然后从结果压缩列表中获取所需的数字:

    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'
    
  • 1

    这个问题有一些结构,它来了 . 我会用这些东西:

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

    首先,list-with-padding是一个有用的概念,所以让我们有一个类型 .

    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  "]
    
  • 5

    这可以使用这些库中的These("represents values with two non-exclusive possibilities")和Align("functors supporting a zip operation that takes the union of non-uniform shapes")来表示:

    import Data.Align
    import Data.These
    
    zipWithDefault :: Align f => a -> b -> f a -> f b -> f (a, b)
    zipWithDefault da db = alignWith (fromThese da db)
    

    salignData.Align 中的其他专业对齐也值得一看 .

    感谢你/ WarDaft,u / gallais和u / sjakobi在r / haskell指出这个答案应该存在于此 .

  • 1

    这应该是诀窍:

    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 ,在你使用时丢弃不再需要的 Just .

  • 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-}
    
  • 4

    您不必比较列表长度 . 尝试将您的zip函数视为只接受一个参数 xs 并返回一个函数的函数,该函数将获取 ys 并执行所需的zip . 然后,尝试编写一个递归函数,仅在 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,请注意你可以将上面的递归变成折叠!

  • 36

    这是另一个解决方案,它可以在无限列表上工作,并且是Prelude的zip函数的简单升级:

    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,谢谢你的启发解决方案!

相关问题