[Haskell-beginners] Padding List with Zeros

Henry Olders henry.olders at mcgill.ca
Thu Sep 16 12:32:00 EDT 2010


On 2010-09-15, at 15:12 , Daniel Fischer wrote:

> On Wednesday 15 September 2010 20:24:09, Hein Hundal wrote:
>> On Wed, 15 Sep 2010 16:23:49, Daniel Fischer wrote:
>>> On Wednesday 15 September 2010 15:15:49, Henry Olders wrote:
>>>> On 2010-09-14, at 19:35 , Lorenzo Isella wrote:
>>>>> Dear All,
>>>>> I still have to find my way with immutable lists and list
>>>>> comprehension. Consider the following lists
>>>>> 
>>>>> A=[0,10,20,30,40,50]
>>>>> B=[0,10,50] (i.e. B is a subset of list A; list A is
>>>>> already ordered in increasing order and so is B).
>>>>> C=[2,1,-5] i.e. there is a corresponding element in C for every
>>>>> element in B.
>>>>> 
>>>>> Now, I would like to define a new list D having length equal
>>>>> to the length of A. The elements of D in the position of the
>>>>> elements of A in common with B are equal to the corresponding
>>>>> entries in C, whereas the other ones are zero i.e.
>>>>> D=[2,1,0,0,0,-5]. How can I achieve that? The first thought
>>>>> that comes to my mind is to define a list of zeros which I
>>>>> would modify according to my needs, but that is not allowed...
>> 
>> Yes, that is not allowed.  First thing I thought of also.
>> 
>>>>> Many thanks
>>>>> 
>>>>> Lorenzo
>>>> 
>>>> Being a real Haskell newby, I can figure out a one-line solution in
>>>> Python, but I don't know how to do something similar in Haskell, or
>>>> even if it's possible. Please correct me if I'm wrong, but there
>>>> does not seem to be a dictionary type in Haskell, and I am not aware
>>>> of how to specify an inline if...else inside a list comprehension. I
>>>> would really appreciate it if someone could show me how to do
>>>> something similar to this Python statement in Haskell.
>>> 
>>> import Data.Maybe
>>> 
>>>>>>> A=[0,10,20,30,40,50]
>>>>>>> B=[0,10,50]
>>>>>>> C=[2,1,-5]
>>> 
>>> These have to be lowercase in Haskell, of course :)
>>> 
>>>>>>> [dict(zip(B,C))[a] if a in B else 0 for a in A]
>>> 
>>> map (fromMaybe 0 . (`lookup` zip b c)) a
>>> 
>>> or, as a list comprehension,
>>> 
>>> [fromMaybe 0 (lookup v dic) | let dic = zip b c, v <- a]
>>> 
>>> Slightly more verbose than the Python.
>>> 
>>> But this doesn't deal with multiple entries (istr that was
>>> mentioned previously in this thread), for
>>> 
>>> a = [0, 10, 10, 20, 30 , 40, 50]
>>> b = [0, 10, 10, 50]
>>> c = [2, 1, 3, -5]
>>> 
>>> neither would produce
>>> 
>>> [2, 1, 3, 0, 0, 0, -5]
>>> 
>>> which I believe would be the desired behavior.
>>> 
>>>> [2, 1, 0, 0, 0, -5]
>>>> 
>>>> Henry
>> 
>> I love the map solution and the lookup solutions--very concise.  Someday
>> perhaps those will occur to me when I look at these problems.
>> 
>> Here is my (extremely) verbose beginner solution.  I think this solution
>> is linear time and it returns the "desired behavior" in Daniel's post.
>> 
>> -- indices v1 v2
>> --    find the elemIndex of v2's elements in v1
>> --    almost equivalent to (map (flip elemIndex v1) v2)
>> --
>> indices v1 v2 = indices' 0 v1 v2
>> indices' iOff (x:xs) (y:ys)
>> 
>>   | x < y = indices' (iOff+1) xs (y:ys)
>>   | x ==y = iOff:(indices' (iOff+1) xs ys)
>>   | x > y = error "indicies:: elem not found"
>> 
>> indices' _  _ [] = []
>> indices' _ [] (y:ys) = error "indices:: elem not found"
>> 
>> 
>> -- makevec 0 indices values
>> --   returns a vector with values filled in at the indices given
>> --
>> makevec _ [] _ = []
>> makevec _ _ [] = error "makevec:: "
>> makevec iOffSet (i:is) (x:xs)
>> 
>>   | iOffSet < i = replicate (i-iOffSet) 0 ++ makevec i (i:is) (x:xs)
>>   | iOffSet ==i = x:(makevec (iOffSet+1) is xs)
>>   | iOffSet > i = error "makevec error"
>> 
>> hisfunc :: [Integer] -> [Integer] -> [Integer] -> [Integer]
>> hisfunc a b c = let front = makevec 0 (indices a b) c
>>   in front ++ replicate (length a - length front) 0
>> 
>> 
>> test1 = hisfunc a b c
>> test2 = hisfunc (a++[70, 90]) b c
>> test3 = hisfunc (a++[70, 90]) (b++[70]) (c++[-14])
>> test4 = hisfunc [0,10,10,20,30,40,50] [0,10,10,50] [2,1,3,-5]
> 
> Somewhat simpler in one go:
> 
> -- Preconditions:
> -- length bs == length cs
> -- as and bs are sorted
> -- bs is a sublist of as
> expand :: (Ord a, Num a) => [a] -> [a] -> [a] -> [a]
> expand as [] _ = map (const 0) as
> expand (a:as) bbs@(b:bs) ccs@(c:cs)
>    | a < b     = 0 : expand as bbs ccs
>    | otherwise = c : expand as bs cs
> expand _ _ _ = []

My thanks to the various contributors to this discussion. Lots of food for thought!

Henry



More information about the Beginners mailing list