首页 > 解决方案 > Haskell 用新数据替换列表中的数据

问题描述

我一直在尝试用列表中的新书替换给定的现有书。新书应该有一个名字、页数、评级,并且应该用 3 个数字显示它每周被借出的次数。更换后的书籍顺序应相同。

data Book = Book { name:: String
                   , pages:: Int, rating:: Float
                   , timesLentEveryWeek:: [Float]
              } deriving (Eq,Ord,Show,Read)

testData1 :: [Book]
testData1 =  [Book "Harry Potter"                    374    9.7   [7, 5, 8],
              Book "Percy Jackson & the Olympians"   530    9.8   [3 , 4, 2],
              Book "Star Wars"                       435    9.5   [9 , 7, 10]]

例如,如果我将Book "Harry Potter" 374 9.7 [7, 5, 8]替换为Book "Don Quixote" 304 8.9 [4, 6, 3]我应该得到结果:

Book "Don Quixote"                     304    8.9   [4, 6, 3],
Book "Percy Jackson & the Olympians"   530    9.8   [3 , 4, 2],
Book "Star Wars"                       435    9.5   [9 , 7, 10]]

我试图通过添加 removeBook 递归函数并通过使用该map函数将元素从一个列表添加到另一个来添加一本书来解决该问题。但是,我没有使用此功能的经验,而且我似乎在实现它时遇到了问题:

removeBook :: String -> [Book] -> [Book]
removeBook n (p:ps)
    | n == name p = removeBook n ps
    | otherwise = p : removeBook n ps


replaceBook :: Book -> Book -> [Book] -> String -> [Book]
replaceBook old new booksData oldBookName = map new removeBook oldBookName booksData

标签: haskell

解决方案


如果你想删除或添加一本书,map帮不了你:一个属性map是它不能改变列表中元素的数量。但是,还有另一种方法可以实现这一点map:只需映射书籍列表的每个元素,检查每本书是否与您的旧书相同,如果是,则将其替换为新书:map (\b -> if b == oldBook then newBook else b) bookList。这应该让您在不更改元素顺序的情况下替换oldBooknewBook

(一个小问题:如果你有重复的书,这最终会替换两本相同的书,而不仅仅是一本。如果这对你来说是个问题,你将需要使用不同的方法——在这种情况下,我会使用递归。)


推荐阅读