我有一个自定义数据对象列表,它使用一个字段total
跟踪每天增加的总价值。自定义数据类型中的另一个字段是值new
。使用csv文件,我已经读取了date
和total
的值,并试图从这些值中计算和设置new
的值。
data item = Item{
date :: Day,
total :: Int,
new :: Int
}
之前我们可以通过压缩输入列表本身来实现这一点,移动一步。
假设您有一个已经用total
值填充的项目列表,您希望更新它以包含正确的new
值(当然是构建一个更新的副本),
type Day = Int
data Item = Item{ -- data Item, NB
date :: Day,
total :: Int,
new :: Int
} deriving Show
calcNews :: [Item] -> [Item]
calcNews [] = []
calcNews totalsOK@(t:ts) = t : zipWith f ts totalsOK
where
f this prev = this{ new = total this - total prev }
我们得到
> calcNews [Item 1 0 0, Item 2 2 0, Item 3 5 0, Item 4 10 0]
[Item {date = 1, total = 0, new = 0},Item {date = 2, total = 2, new = 2},
Item {date = 3, total = 5,new = 3},Item {date = 4, total = 10, new = 5}]
当然是zipWith f x y == map ((a,b) -> f a b) $ zip x y
,正如我们在你之前的问题中看到的,所以zipWith
就像一个二进制map
。
有时(虽然这里不是)我们可能还需要访问先前计算的值,以计算下一个值。为此,我们可以将结果本身的移位版本压缩输入来创建结果:
calcNews2 :: [Item] -> [Item]
calcNews2 [] = []
calcNews2 (t:totalsOK) = newsOK
where
newsOK = t : zipWith f totalsOK newsOK
f tot nw = tot{ new = total tot - total nw }