haskell - 如何替换元组
问题描述
如何替换列表中元组中的值?
type Person =(String, Float, Float, [Int])
data :: [Person]
data :: [("Emma", 16, 56, [3,4,6]), ("Ari", 20, 65, [7,4,9]), ("Tyler", 32, 84, [4,6,2]),
("Beau", 13, 55,[8,2,6]), ("Jaylen", 27, 88, [5,2,8])]
如果我想替换("Tyler", 32, 84, [4,6,2])
为("Anna", 19, 53, [3,3,8])
so 当调用函数时输出将显示数据为:
[("Emma", 16, 56, [3,4,6]), ("Ari", 20, 65, [7,4,9]), ("Anna", 19, 53, [3,3,8]), ("Beau", 13, 55,[8,2,6]), ("Jaylen", 27, 88, [5,2,8])]
我会用什么方法来做到这一点?提前致谢 :)
解决方案
首先,您需要决定要将元组的哪一部分视为键。在这里,我假设元组的第一个组件(String
)将充当键。
接下来,您需要选择一个接口。你想如何调用你的替换函数?在 Haskell 中,这归结为决定函数的类型。假设我们希望该函数简单地将选择要替换的元组的键、新元组和旧元组列表作为参数,然后生成一个新的元组列表。该函数的类型签名将读取:
replace :: String -> Person -> [Person] -> [Person]
最后,你当然需要编写你的函数。我们可以通过简单地遍历输入元组列表来做到这一点。我们可以考虑三种情况。
首先,输入列表为空的情况。那么输出列表也应该是空的:
replace key new [] = []
接下来,输入列表包含至少一个元组并且第一个元组的键部分与搜索键匹配的情况。在这种情况下,我们会忘记第一个元组并将其替换为新元组:
replace key new ((k, _, _, _) : tl) | k == key = new : tl
(这里我们选择在找到匹配项后中止遍历。如果您预计会出现输入列表中存在多个匹配项并且想要替换所有匹配元组的情况,那么您应该调整第二种情况并在尾部递归——就像第三种情况一样;见下文。)
最后,输入列表包含至少一个元组且第一个元组的键与搜索键不匹配的情况。在这种情况下,我们将第一个元组留在列表的头部,并递归地尝试在列表的尾部进行替换:
replace key new (hd@(k, _, _, _) : tl) | k /= key = hd : replace key new tl
(请注意,我们也可以将最后一个案例的左侧简单地写为replace key new (hd : tl)
。也就是说,测试k /= key
是多余的,因为如果它失败,则将选择第二种情况。)
在你的例子上测试它
persons :: [Person]
persons =
[ ("Emma" , 16, 56, [3, 4, 6])
, ("Ari" , 20, 65, [7, 4, 9])
, ("Tyler" , 32, 84, [4, 6, 2])
, ("Beau" , 13, 55, [8, 2, 6])
, ("Jaylen", 27, 88, [5, 2, 8])
]
给出:
> replace "Tyler" ("Anna", 19, 53, [3,3,8]) persons
[("Emma",16.0,56.0,[3,4,6]),("Ari",20.0,65.0,[7,4,9]),("Anna",19.0,53.0,[3,3,8]),
("Beau",13.0,55.0,[8,2,6]),("Jaylen",27.0,88.0,[5,2,8])]
上面的定义replace
可能有点冗长。可以说,一种更惯用的写作方式是:
replace' key new = go
where
go [] = []
go (hd@(k, _, _, _) : tl) | k == key = new : tl
| otherwise = hd : go tl
对于在找到匹配项后不想中止遍历的情况,replace
可以很容易地写成折叠:
replace'' key new = foldr go []
where
go hd@(k, _, _, _) tl' | k == key = new : tl'
| otherwise = hd : tl'
或者更好的是,一张地图:
replace''' key new = map f
where
f p@(k, _, _, _) | k == key = new
| otherwise = p
推荐阅读
- angularjs - 如何使用 if 语句实现 for 循环
- r - 从字符向量中提取所有匹配模式
- ios - 为什么之前调用 reloadRows 时 UITableView setContentOffset 不能正常工作?
- binding - 如何在 Angular 上为来自 HTTP 表的动态数据实现分页
- pyqt5 - PyQt5:通过实现QGraphicsScene、QGraphicsView和QGraphicsItem,使用mouseEvents绘制多个矩形
- reactjs - 笑话:添加元素后功能组件数组列表未映射
- design-patterns - 以最通用的方式对依赖于两种主要类型(或其子类型)的行为进行建模的最佳架构是什么?
- c# - EF Core 2.2 执行 SQL 存储过程在 SQL Server 管理中成功执行时超时
- php - 每个单个产品页面 woocommerce 的不同自定义数量
- java - 如何重构此方法以将其认知复杂性从 21 降低到允许的 15?