首页 > 解决方案 > 如何替换元组

问题描述

如何替换列表中元组中的值?

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])]我会用什么方法来做到这一点?提前致谢 :)

标签: haskell

解决方案


首先,您需要决定要将元组的哪一部分视为键。在这里,我假设元组的第一个组件(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

推荐阅读