替换Haskell中的各个列表元素?

mac*_*ian 24 state haskell list

我有一个元素列表,我希望更新它们:

由此: ["Off","Off","Off","Off"]

对此: ["Off","Off","On","Off"]

由于我对Haskell有点新,我一直在(x:xs)!!y使用该函数提取和更新单个组件:

replace y z [] = []
replace y z (x:xs)
  | x==y           = z:replace y z xs
  | otherwise      = x:replace y z xs
Run Code Online (Sandbox Code Playgroud)

然后在ghci中输入以下内容: (replace "Off" "On" ["Off",'Off","Off","Off"]) !! 2

我得到以下内容: "On"

我似乎能够提取和转换列表的元素,但我似乎无法获得转换单个元素的列表.

任何有关此事的帮助将不胜感激.

Don*_*art 49

通常,您可以通过拆分列表,替换元素并将其重新连接在一起来修改列表的元素.

要在索引处拆分列表,我们有:

 splitAt :: Int -> [a] -> ([a], [a]) 
Run Code Online (Sandbox Code Playgroud)

您可以使用它来分解列表,如下所示:

 > splitAt 2 ["Off","Off","Off","Off"] 
 (["Off","Off"],["Off","Off"])
Run Code Online (Sandbox Code Playgroud)

现在你只需要弹出snd列表组件的head元素.这可以通过模式匹配轻松完成:

 > let (x,_:ys) = splitAt 2 ["Off","Off","Off","Off"]
 > x
 ["Off","Off"]
 > ys
 ["Off"]
Run Code Online (Sandbox Code Playgroud)

您现在可以一起加入列表,并带有"开":

 > x ++ "On" : ys
 ["Off","Off","On","Off"]
Run Code Online (Sandbox Code Playgroud)

我会留给你把这些碎片组合成一个单独的功能.


作为样式注释,我建议使用新的自定义数据类型,而不是String使用切换:

 data Toggle = On | Off deriving Show
Run Code Online (Sandbox Code Playgroud)


Dav*_*rak 29

更改第n个元素

许多语言中的常见操作是分配给数组中的索引位置.在python中你可能会:

>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]
Run Code Online (Sandbox Code Playgroud)

镜头包给出与此功能(.~)操作.虽然与python不同,原始列表不会发生变异,而是返回一个新列表.

> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]
Run Code Online (Sandbox Code Playgroud)

element 3 .~ 9只是一个功能,(&)操作员,镜头包的一部分 ,只是反向功能应用.这里有更常见的功能应用.

> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]
Run Code Online (Sandbox Code Playgroud)

对任意嵌套Traversables 再次赋值再次完美.

> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]
Run Code Online (Sandbox Code Playgroud)

要么

> set (element 3) 9 [1,2,3,4,5,6,7]
Run Code Online (Sandbox Code Playgroud)

或者,如果您想要影响多个元素,您可以使用:

> over (elements (>3)) (const 99) [1,2,3,4,5,6,7]
> [1,2,3,4,99,99,99]
Run Code Online (Sandbox Code Playgroud)

使用其他类型然后列表

这不仅限于列表,但它适用于任何作为Traversable类型类实例的数据类型.

举例来说,相同的技术适用于标准 容器包的.

 > import Data.Tree
 > :{
 let
  tree = Node 1 [
       Node 2 [Node 4[], Node 5 []]
     , Node 3 [Node 6 [], Node 7 []]
     ]
 :}
> putStrLn . drawTree . fmap show $ tree
1
|
+- 2
|  |
|  +- 4
|  |
|  `- 5
|
`- 3
   |
   +- 6
   |
   `- 7
> putStrLn . drawTree . fmap show $ tree & element 1 .~ 99
1
|
+- 99
|  |
|  +- 4
|  |
|  `- 5
|
`- 3
   |
   +- 6
   |
   `- 7
> putStrLn . drawTree . fmap show $ tree & element 3 .~ 99
1
|
+- 2
|  |
|  +- 4
|  |
|  `- 99
|
`- 3
   |
   +- 6
   |
   `- 7
> putStrLn . drawTree . fmap show $ over (elements (>3)) (const 99) tree
1
|
+- 2
|  |
|  +- 4
|  |
|  `- 5
|
`- 99
   |
   +- 99
   |
   `- 99
Run Code Online (Sandbox Code Playgroud)


Phi*_* JF 16

我不确定你要做什么.如果您只需要生成["关闭","关闭","开启","关闭"],您可以明确地执行此操作.一般来说,应该避免在haskell中修改状态.

也许你想要的是一个"修改"(生成一个具有不同值的新元素)列表的第n个元素的函数?唐对这类问题给出了非常一般的解决方法.您还可以使用显式递归:

 replaceNth :: Int -> a -> [a] -> [a]
 replaceNth _ _ [] = []
 replaceNth n newVal (x:xs)
   | n == 0 = newVal:xs
   | otherwise = x:replaceNth (n-1) newVal xs
Run Code Online (Sandbox Code Playgroud)

Haskell为列表操作提供了出色的功能.如果你不熟悉它们filter,那么/ mapfoldr/ foldl都值得关注,列表理解也是如此.

  • 考虑更通用的`modifyNth :: Int -> (a -> a) -> [a] -> [a]`,它接受一个函数来修改元素,而不是一个硬编码的新值。这个函数现在可以实现为`replaceNth n newVal = modifyNth n (const newVal)` (4认同)

Cri*_*cia 6

这是一个完美运作的单线

replace pos newVal list = take pos list ++ newVal : drop (pos+1) list
Run Code Online (Sandbox Code Playgroud)

我似乎没有效率在haskell做这种事情.


mhw*_*bat 5

这是我一直在使用的一些代码:

-- | Replaces an element in a list with a new element, if that element exists.
safeReplaceElement
  -- | The list
  :: [a]
  -- | Index of the element to replace.
  -> Int
  -- | The new element.
  -> a
  -- | The updated list.
  -> [a]
safeReplaceElement xs i x =
  if i >= 0 && i < length xs
    then replaceElement xs i x
    else xs


-- | Replaces an element in a list with a new element.
replaceElement
  -- | The list
  :: [a]
  -- | Index of the element to replace.
  -> Int
  -- | The new element.
  -> a
  -- | The updated list.
  -> [a]
replaceElement xs i x = fore ++ (x : aft)
  where fore = take i xs
        aft = drop (i+1) xs
Run Code Online (Sandbox Code Playgroud)