如何生成这样的列表

时间:2011-10-26 02:52:56

标签: haskell

假设我有以下列表列表

a = [[1 2]  
     [4 2]
     [7 3]]

我想生成一个像这样的列表

makeRow :: [[Int]] -> [Int]

  0 1 2  3 4 5  6 7 8 9  
[-1 0 0 -1 0 0 -1 0 0 0]

因此列表将从索引1开始有2 0,从索引4开始有2 0,从索引7开始有3个0。没有0的地方默认为-1

4 个答案:

答案 0 :(得分:2)

所以,你绝对可以使用列表理解,但这里没有。

import Data.List

makeRow :: [[Int]] -> [Int]
makeRow arr = place tabulate length
              where tabulate = foldl' expand [] arr
                    expand st [idx,num] = st++[idx..(idx+num-1)]
                    length = last tabulate

place :: [Int] -> Int -> [Int] 
place rules l = foldr ins [] [0..l]
                where ins i st = if elem i rules then 0:st else (-1):st

因此makeRow首先将规则扩展为应设置为-1的索引列表。然后,在每个索引上放置循环,如果它在我们扩展的规则列表中,则添加0,否则添加-1。

*Main> makeRow [[1,2],[4,2],[7,3]]
[-1,0,0,-1,0,0,-1,0,0,0]

我很乐意看到有人在列表理解中尝试这一点。我确信有更优雅的方法可以做到这一点,但这将完成工作。我会把它作为OP的一个练习,以弄清楚如何写出这个不那么重要的东西。

(单线版)

import Data.List

makeRow :: [[Int]] -> [Int]
makeRow arr = [if any (\[i,n] -> elem a [i..(i+n-1)]) arr 
               then 0 else -1 | a <- [0..((sum $ last arr)-1)] ]

我坚持认为,将这个功能变成单行的技巧的交易可读性并不是一个很好的做法。但是,我仍然希望真正的巫师会向我展示一种更简洁的方法。

答案 1 :(得分:0)

这个更短,可能更容易理解。尽管如此,仍然没有列表理解。 ;-)

makeRow = go 0
  where go _ [] = []
        go i ([j,n]:xs) = replicate (j-i) (-1) ++ replicate n 0 ++ go (j+n) xs

如果不能保证所需字段不会重叠或者它们是有序的,则需要添加错误检查和输入清理。

答案 2 :(得分:0)

您知道如何使用非Haskell语言生成此类列表吗?根据您的操作,将while循环转换为尾递归函数可能相当直接。 (在大多数情况下,结果可能不是完全惯用的,但知道如何进行这些转换非常有用)

答案 3 :(得分:0)

当然不是最简洁的方法,但我觉得这非常简单易懂

makeRow :: [[Int]] -> [Int]
makeRow []            = []
makeRow ([0,n]:pairs) = replicate n 0 ++ makeRow (map (decrementBy n) pairs)
makeRow pairs         =            -1 :  makeRow (map (decrementBy 1) pairs)
    where decrementBy n [x,y] = [x-n,y]