Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 替换Haskell中的单个列表元素?_List_Haskell_State - Fatal编程技术网

List 替换Haskell中的单个列表元素?

List 替换Haskell中的单个列表元素?,list,haskell,state,List,Haskell,State,我有一个元素列表,我希望更新它们: 从此处:[“关”、“关”、“关”、“关”] 对此:[“关”、“关”、“开”、“关”] 由于我对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 然后在ghci中输入以下内容:(将“关”替换为“开

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

从此处:
[“关”、“关”、“关”、“关”]

对此:
[“关”、“关”、“开”、“关”]

由于我对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
然后在ghci中输入以下内容:
(将“关”替换为“开”[“关”、“关”、“关”)!!2

我得到以下信息:
“On”

我似乎能够提取和转换列表中的元素,但我似乎无法在转换单个元素的情况下获得列表


如果您能提供有关此问题的任何帮助,我们将不胜感激。

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

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

 splitAt :: Int -> [a] -> ([a], [a]) 
您可以使用它来分解列表,如下所示:

 > splitAt 2 ["Off","Off","Off","Off"] 
 (["Off","Off"],["Off","Off"])
现在,您只需要弹出列表中
snd
组件的head元素。这可以通过模式匹配轻松完成:

现在,您可以使用“On”将列表重新连接到一起:

我将把这些部分放到一个函数中


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

 data Toggle = On | Off deriving Show

我不知道你想做什么。如果你只需要生成[“关”、“关”、“开”、“关”],你可以显式地完成。一般来说,应该避免修改haskell中的状态

也许您想要的是一个函数来“修改”(生成一个具有不同值的新元素)列表的第n个元素?Don给出了解决此类问题的一种非常通用的方法。 还可以使用显式递归:

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

Haskell为列表操作提供了非常好的特性。如果你不知道它们已经过时了。<代码>过滤器>代码>地图> <代码>,和<代码> FordDR <代码> >代码> FoLDL都是值得看的,就像列表理解一样。

< P>我认为你应该考虑使用除列表之外的数据结构。例如,如果你只想拥有一个STATe四个开/关开关中的一个,然后:

data State = St { sw1, sw2, sw3, sw4 :: Bool }

对于动态数量的开关,考虑从“代码>开关名称< /代码>到<代码> BOOL 的映射。

< P>这里是我使用的一些代码:

-- | 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
——|使用新元素替换列表中的元素(如果该元素存在)。
安全替换元件
--|名单
:[a]
--|要替换的元件的索引。
->Int
--|新元素。
->a
--|更新的列表。
->[a]
安全替换元素xs i x=
如果i>=0&&iInt
--|新元素。
->a
--|更新的列表。
->[a]
替换元素xs i x=fore++(x:aft)
其中fore=取i x
后=下降(i+1)x

我认为这是一种更优雅的替换单个元素的方法:

setelt:: Int -> [a] -> a -> [a]

setelt i list newValue = 
  let (ys,zs) = splitAt i-1 list in  ys ++ newValue ++ tail zs
存在输入错误处理。 因此,如果索引i超出边界,haskell将显示错误的输出。(注意:在haskell中,索引从1开始)

拥抱的行为如下:

Main> setelt 1 [1,2,3] 9
[9,2,3]
Main> setelt 3 [1,2,3] 9
[1,2,9]
Main> setelt 0 [1,2,3] 9
[9,2,3]
Main> setelt 4 [1,2,3] 9
[1,2,3,9]
Program error: pattern match failure: tail []
在您的服务中处理错误:

setelt i y newValue = 
    if and [i>0, i<= length y]
    then let (ys,zs) = splitAt (i-1) y in  ys ++ [newValue] ++ tail zs
    else y
setelt i y newValue=
如果和[i>0,i改变第n个元素
许多语言中的一个常见操作是在数组中指定索引位置。在python中,您可能:

>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]
包使用
(.~)
操作符提供此功能。虽然与python中不同,原始列表没有变化,而是返回一个新列表

> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]
元素3.~9
只是一个函数,
(&)
操作符是 软件包,只是一个反向函数应用程序。这里是一个更常见的函数应用程序

> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]
赋值同样适用于
Traversable
s的任意嵌套

> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]

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

> over (elements (>3)) (const 99) [1,2,3,4,5,6,7]
> [1,2,3,4,99,99,99]
使用类型而不是列表 这不仅仅局限于列表,它还可以处理任何作为typeclass实例的数据类型

举个例子,同样的技术也适用于标准的形式 包裹


这是一个工作完美的单内衬

replace pos newVal list = take pos list ++ newVal : drop (pos+1) list

在haskell中,我似乎没有效率去做这类事情。

这个答案来得很晚,但我想我应该分享一下我认为的一种有效的方法,来替换haskell列表中的第n个元素。我是haskell的新手,我想我应该参与进来

set
函数将列表中的第n个元素设置为给定值:

set' :: Int -> Int -> a -> [a] -> [a]
set' _ _ _ [] = []
set' ind curr new arr@(x:xs)
    | curr > ind = arr
    | ind == curr = new:(set' ind (curr+1) new xs)
    | otherwise = x:(set' ind (curr+1) new xs)

set :: Int -> a -> [a] -> [a]
set ind new arr = (set' ind 0 new arr)
set
遍历一个列表时,它会将列表分开,如果当前索引是给定的
n
它会将上一个元素与给定的新值结合起来,否则,它会将上一个元素与该索引列表中的旧值结合起来。

实际上,在许多情况下(并非总是如此)在使用列表的地方,Data.Vector是更好的选择


它附带了一个更新功能,请参阅,它可以完全满足您的需要。

对于动态数量的开关,我建议使用
向量
,或者可能是
IntMap
@John Right,根据您的具体需要,映射可以是Map、IntMap或HashMap(甚至其他)。为什么你会建议使用向量呢?如果每次运行都是静态的,当然可以,但是如果交换机的数量确实需要增加或减少,那么向量就做不好。
++
的第二个参数长时性能差。这就是
ShowS
的原因;递归方法的性能可能会更好。Con在更通用的
modifyNth::Int->(a->a)->[a]->[a]
中,它使用一个函数来修改元素,而不是硬编码的新值。此函数现在可以实现为
replaceNth n newVal=modifyNth n(const newVal)
这对于替换最后一个e不起作用
> over (elements (>3)) (const 99) [1,2,3,4,5,6,7]
> [1,2,3,4,99,99,99]
 > 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
replace pos newVal list = take pos list ++ newVal : drop (pos+1) list
set' :: Int -> Int -> a -> [a] -> [a]
set' _ _ _ [] = []
set' ind curr new arr@(x:xs)
    | curr > ind = arr
    | ind == curr = new:(set' ind (curr+1) new xs)
    | otherwise = x:(set' ind (curr+1) new xs)

set :: Int -> a -> [a] -> [a]
set ind new arr = (set' ind 0 new arr)