简体   繁体   English

处理Haskell中的列表列表

[英]Working over a list of lists in Haskell

I'm a bit of a beginner to Haskell so I'm struggling a little with the strict type stuff, just wondering if someone can help me with a function I'm trying to build. 我是Haskell的初学者,所以我在使用严格类型的东西时会苦苦挣扎,只是想知道是否有人可以帮助我使用我正在尝试构建的函数。 Basically, it takes a list of lists, for example: 基本上,它需要一个列表列表,例如:

[[1,2,3], [7,6,8], [0,3,4]]

and adds them together into one list translating the later lists by the number of positions along it is. 并将它们一起添加到一个列表中,通过沿着它的位置数来翻译后面的列表。 So working on the example list it would actually be doing something like: 因此,在示例列表上工作实际上将执行以下操作:

foldl (zipWith +) [] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]

Here's my current function (which gets type errors): 这是我当前的函数(获取类型错误):

    addLists :: [[Integer]] -> [Integer]
    addLists [[]] = []
    addLists [[x]] = [x]
    addLists [x:xs] = zipWith (+) [x] ([0]++ (addLists xs))

Note that ([0]++) is the same as (0:) , which will make it look tidier and save us a nanosecond or two. 请注意, ([0]++)(0:)相同,这将使它看起来更整洁,并为我们节省一两纳秒。 (I'm joking with the nanosecond thing - no human can tell when something's a nanosecond faster, but it is nicer this way anyway.) (我正在用纳秒级的东西开玩笑 - 没有人能分辨出什么东西的速度快一纳秒,但无论如何它都更好。)

Let's first think about making the lists you need. 让我们首先考虑制作您需要的列表。 We want 我们想要

postponeLists [[1,2,3], [7,6,8], [10,20,30,40]] 
             = [[1,2,3], [0,7,6,8], [0,0,10,20,30,40]]
             = [1,2,3] : ones that should have zero in front of them

That's enough information for a definition: 这是足够的定义信息:

postponeLists [] = []
postponeLists (l:ls) = l : map (0:) (postponeLists ls)

Now you said 现在你说

foldl (zipWith +) [] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]

but you mean 但你的意思是

foldl (zipWith (+)) [] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]

but unfortunately, that gives you [] because zipWith stops as soon as any of the lists run out of elements. 但遗憾的是,这会给你[]因为zipWith任何列表用完元素, zipWith停止。 We need some way of zipping them that doesn't stop. 我们需要某种方式来压缩它们并不会停止。

Solution 1: find the longest one, make them all that maxlength using take maxlength.(++ repeat 0) 解决方案1:找到最长的一个,使用take maxlength.(++ repeat 0)将它们全部maxlength take maxlength.(++ repeat 0)
Solution 2: write another zipWith function that doesn't stop. 解决方案2:编写另一个不停止的zipWith函数。

I prefer solution 2. Let's look at the definition of zipWith 我更喜欢解决方案2.让我们来看看zipWith定义

zipWith :: (a->b->c) -> [a]->[b]->[c]
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
zipWith _ _      _      = [] -- here's the problem - it stops as soon as any list is empty

OK, let's not stop then: 好吧,我们不要停下来:

zipWithMore :: (a -> a -> a) -> [a] -> [a] -> [a]
zipWithMore f (a:as) (b:bs) = f a b : zipWithMore f as bs
zipWithMore f []      bs      = bs -- if there's more in bs, use that
zipWithMore f as      []      = as -- if there's more in as, use that

Now you can replace zipWith (+) with zipWithMore (+) . 现在你可以用zipWith (+)替换zipWithMore (+) I'll leave the punchline to you. 我会给你留下妙语。

I think this does what you want 我认为这样做你想要的

import Data.List (transpose)

addLists :: Num a => [[a]] -> [a]
addLists xs = map sum . transpose $ zipWith (\n x -> replicate n 0 ++ x) [0..] xs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM