我有以下代码:
let numbers = [[1],[2],[3],[4]]
我想将“3”附加到列表([3]
)的索引2处的子列表中,如下所示:
(numbers !! 2) ++ [3]
得到这个:
numbers = [[1],[2],[3,3],[4]]
但我很困惑:P有什么想法吗?
答案 0 :(得分:1)
其他方式是通过拍摄和放弃
{{1}}
drop 3 first array - > [[4]]
[[1],[2]] ++ [[3] ++ [3]] ++ [[4]] = [[1],[2],[3,3],[4] ]
答案 1 :(得分:0)
如果您难以编写递归更新函数,则可以将列表结构转换为具有zip
的合成索引数组
zip [0..] [[1],[2],[3],[4]]
并根据索引编写concat版本,就像使用索引数组的其他语言一样
appendAt n a = map (\(i,x) -> if i==n then x++[a] else x) . zip [0..]
然后,
appendAt 2 3 numbers
会给你想要的结果。
答案 2 :(得分:0)
正如chi已经评论过,在现代Haskell中对结构进行此类更新的最佳方法是使用 lense combinators ,具体来说,ix
:
Prelude Control.Lens> let numbers = [[1],[2],[3],[4]]
Prelude Control.Lens> numbers & ix 2 %~ (++[3])
[[1],[2],[3,3],[4]]
(不要害怕镜头。主lens
包很大且依赖性很大,但其大部分杀手功能,包括ix
,也包含在兼容和更小microlens
package。)
答案 3 :(得分:0)
正如其他人所说,在Haskell中,您通常不会修改数据结构。相反,你将它拆开,引入你的修改,并将它重新组合在一起,以创建一个包含变化的新数据结构。
为了更改特定的列表元素,我发现splitAt
函数对于拆分列表很有用。例如,如果将列表拆分为索引2,则会生成以下一对列表:
> splitAt 2 numbers
( [[1],[2]] , [[3],[4]] ) -- spaces added to make it clearer
请注意,您要更改的元素是第二个列表的第一个元素。您可以使用Haskell的模式匹配来方便地处理该对:
> let (a, x:b) = splitAt 2 numbers
> a -- initial part of list
[[1],[2]]
> x -- element to change
[3]
> b -- rest of list
[[4]]
> a ++ x : b -- put list back together unchanged
[[1],[2],[3],[4]]
> a ++ (x ++ [3]) : b -- put list together w/ modification
[[1],[2],[3,3],[4]]
如果将其转换为Haskell函数,它可能看起来像:
appendSublist :: Int -> [a] -> [[a]] -> [[a]]
appendSublist idx y lst
= let (a, x:b) = splitAt idx lst
in a ++ (x ++ y) : b
你会像这样使用:
> appendSublist 2 [3] numbers
[[1],[2],[3,3],[4]]
这个基本模式:
let (a, x:b) = splitAt idx lst in a ++ (...replacement for x...) : b
值得记住,因为它非常有用。
最终,您可能希望学习使用lens
库进行此类操作。镜头更简洁,更灵活(即,适用于各种事物,而不仅仅是特定的列表项目),但是有一个非常大的学习曲线,你可以从@ leftaroundabout的答案猜测。