简体   繁体   中英

How to replace a tuple

How does one go about replacing values in a tuple in a list?

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])]

If I wanted to replace ("Tyler", 32, 84, [4,6,2]) with ("Anna", 19, 53, [3,3,8]) so when the function is called the output would show the data as:

[("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])] what method would I use to do this? Thanks in advance:)

First, you need to decide on what part of your tuples you want to treat as keys. Here, I am assuming that the first component of the tuple (the String ) will act as the key.

Next, you need to pick an interface. How do you want to invoke your replacement function? In Haskell, this boils down to deciding on a type for your function. Let's say we want the function to simply take the key to select the tuple to replace, the new tuple and the list of old tuples as arguments and then produce a new list of tuples. A type signature for the function will then read:

replace :: String -> Person -> [Person] -> [Person]

Finally, you need to write your function of course. We could do so by simply traversing the list of input tuples. We could proceed by considering three cases.

First, the case in which the input list is empty. Then the output list should also be empty:

replace key new [] = []

Next, the case in which the input list contains at least one tuple and the key part of the first tuple matches the search key. In that case we forget about that first tuple and have it replaced by the new tuple:

replace key new ((k, _, _, _) : tl) | k == key = new : tl

(Here we have chosen to abort the traversal once we have found a match. If you anticipate that there will be situation in which there is more than one match in your input list and you want to replace all matching tuples, then you should adapt the second case and recurse on the tail—just as in the third case; see below.)

Finally, the case in which the input list contains at least one tuple and the key of the first tuple does not match the search key. In that case we leave the first tuple at the head of the list and recursively try to make a replacement in the tail of the list:

replace key new (hd@(k, _, _, _) : tl) | k /= key = hd : replace key new tl

(Note that we can also write the left-hand side of the final case simply as replace key new (hd: tl) . That is, the test k /= key is redundant, because if it would fail the second case would have been selected.)

Testing it on your example

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])
  ]

gives:

> 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])]

The definition of replace above is perhaps a bit verbose. Arguably, a more idiomatic way of writing it would be:

replace' key new = go
 where
  go [] = []
  go (hd@(k, _, _, _) : tl) | k == key  = new : tl
                            | otherwise = hd : go tl

For the situation in which you don't want to abort the traversal after you've found a match, replace can be easily written as a fold:

replace'' key new = foldr go []
 where
  go hd@(k, _, _, _) tl' | k == key  = new : tl'
                         | otherwise = hd : tl'

Or better yet, a map:

replace''' key new = map f
 where
  f p@(k, _, _, _) | k == key  = new
                   | otherwise = p

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM