list 替换 Haskell 中的单个列表元素?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5852722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace individual list elements in Haskell?
提问by maclunian
I have a list of elements and I wish to update them:
我有一个元素列表,我希望更新它们:
from this: ["Off","Off","Off","Off"]
由此: ["Off","Off","Off","Off"]
to this: ["Off","Off","On","Off"]
对此: ["Off","Off","On","Off"]
As I am somewhat new to Haskell, I have been using (x:xs)!!y
to extract and update individual components using the function:
由于我对 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
and then entering the following in ghci: (replace "Off" "On" ["Off",'Off","Off","Off"]) !! 2
然后在ghci中输入以下内容: (replace "Off" "On" ["Off",'Off","Off","Off"]) !! 2
I get the following: "On"
我得到以下信息: "On"
I seem to be able to extract and convert elements of a list but I can't seem to get a list up with the single element converted.
我似乎能够提取和转换列表的元素,但我似乎无法通过转换的单个元素获得列表。
Any help regarding this matter would be appreciated.
任何有关此事的帮助将不胜感激。
采纳答案by Philip JF
I'm not sure what you are trying to do. If you only need to generate ["Off","Off","On","Off"] you can do it explicitly. Generally speaking, one should avoid modifying state in haskell.
我不确定你想做什么。如果你只需要生成 ["Off","Off","On","Off"] 你可以明确地做。一般来说,应该避免在haskell中修改状态。
Perhaps what you want is a function to "modify" (generate a new element with a different value) the nth element of a list? Don gives a very general approach to this kind of problem. You can also use explicit recursion:
也许您想要的是一个函数来“修改”(生成具有不同值的新元素)列表的第 n 个元素?唐对这类问题给出了一个非常通用的方法。您还可以使用显式递归:
replaceNth :: Int -> a -> [a] -> [a]
replaceNth _ _ [] = []
replaceNth n newVal (x:xs)
| n == 0 = newVal:xs
| otherwise = x:replaceNth (n-1) newVal xs
Haskell provides excellent features for list manipulation. If you dont know them already filter
, map
, and foldr
/foldl
are all worth looking at, as are list comprehensions.
Haskell 为列表操作提供了出色的功能。如果您还不知道它们filter
,map
, 和foldr
/foldl
都值得一看,列表推导也是如此。
回答by Don Stewart
Typically, you modify elements of a list by splitting the list, replacing an element, and joining it back together.
通常,您可以通过拆分列表、替换元素并将其重新连接在一起来修改列表的元素。
To split a list at an index, we have:
要在索引处拆分列表,我们有:
splitAt :: Int -> [a] -> ([a], [a])
which you can use to break up a list, like so:
您可以使用它来分解列表,如下所示:
> splitAt 2 ["Off","Off","Off","Off"]
(["Off","Off"],["Off","Off"])
now you just need to pop the head element of the snd
component of the list. This is easily done with pattern matching:
现在你只需要弹出snd
列表组件的头部元素。这可以通过模式匹配轻松完成:
> let (x,_:ys) = splitAt 2 ["Off","Off","Off","Off"]
> x
["Off","Off"]
> ys
["Off"]
you can now join the list back together, with an "On":
您现在可以使用“On”将列表重新连接在一起:
> x ++ "On" : ys
["Off","Off","On","Off"]
I'll leave it to you to put those pieces together into a single function.
我会让你把这些部分放在一个单一的函数中。
As a style note, I'd suggest using a new custom data type, instead of String
for your toggles:
作为样式说明,我建议使用新的自定义数据类型,而不是String
用于切换:
data Toggle = On | Off deriving Show
回答by Davorak
Changing the nth element
更改第 n 个元素
A common operation in many languages is to assign to an indexed position in an array. In python you might:
许多语言中的一个常见操作是分配给数组中的索引位置。在 python 中,你可能会:
>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]
The
lenspackage gives this functionality with the (.~)
operator. Though unlike in python the original list is not mutated, rather a new list is returned.
该
镜头包给出与此功能(.~)
操作。尽管与 python 不同,原始列表没有改变,而是返回一个新列表。
> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]
element 3 .~ 9
is just a function and the (&)
operator, part of the
lenspackage, is just reverse function application. Here it is with more common function application.
element 3 .~ 9
只是一个函数,(&)
操作符是镜头包的一部分
,只是反向函数应用。这里是比较常见的功能应用。
> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]
Assignment again works perfectly fine with arbitrary nesting of Traversable
s.
对于Traversable
s 的任意嵌套,赋值再次工作得很好。
> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]
or
或者
> set (element 3) 9 [1,2,3,4,5,6,7]
Or if you want to effect multiple elements you can use:
或者,如果您想影响多个元素,您可以使用:
> over (elements (>3)) (const 99) [1,2,3,4,5,6,7]
> [1,2,3,4,99,99,99]
Working with types other then lists
使用列表以外的类型
This is not just limited to lists however, it will work with any datatype that is an instance of the Traversabletypeclass.
然而,这不仅限于列表,它还适用于作为Traversable类型类实例的任何数据类型。
Take for example the same technique works on treesform the standard containerspackage.
> 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
回答by Cristian Garcia
Here is a one liner that works perfectly
这是一个完美的单衬
replace pos newVal list = take pos list ++ newVal : drop (pos+1) list
I doesn't seem efficient to do this kind of things in haskell.
我在haskell中做这种事情似乎效率不高。
回答by mhwombat
Here's some code that I've been using:
这是我一直在使用的一些代码:
-- | 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
回答by Zsolt Szatmari
回答by Thomas M. DuBuisson
I think you should consider using a data structure other than List. For example, if you just want to have a state of four on/off switches then:
我认为您应该考虑使用 List 以外的数据结构。例如,如果您只想拥有四个开/关开关的状态,则:
data State = St { sw1, sw2, sw3, sw4 :: Bool }
For a dynamic number of switches then consider a mapping from switch name
to Bool
.
对于动态数量的开关,请考虑从switch name
到的映射Bool
。
回答by Ziai
I believe this is more elegant way of replacing an individual element:
我相信这是替换单个元素的更优雅的方式:
setelt:: Int -> [a] -> a -> [a]
setelt i list newValue =
let (ys,zs) = splitAt i-1 list in ys ++ newValue ++ tail zs
There is input error handling. So if index iis out of boundaries haskell will show wrong output. (Note: in Haskell indexing starts from 1 onwards)
有输入错误处理。因此,如果索引i超出边界,haskell 将显示错误的输出。(注意:在 Haskell 中索引从 1 开始)
Hugs would behave as follows:
拥抱的行为如下:
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 []
Error handling at your service:
为您服务的错误处理:
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
if index you give is wrong it returns original list.
如果您提供的索引错误,则返回原始列表。
回答by theideasmith
This answer arrives quite late, but I thought I'd share what I think is an efficientway of replacing the nth
element in a list in Haskell. I'm new to Haskell and thought I'd pitch in.
这个答案来得很晚,但我想我会分享我认为在 Haskell中替换列表中元素的有效方法nth
。我是 Haskell 的新手,我想我会加入。
The set
function setsthe nth element in a list to a given value:
该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)
As set
traverses a list, it breaks the list apart and if the current index is the given n
it combines the previous element with the given new value, otherwise, it combines the previous element with the old value in the list for that index.
在set
遍历列表时,它将列表分开,如果当前索引是给定的n
,它将前一个元素与给定的新值组合,否则,它将前一个元素与该索引的列表中的旧值组合。