Haskell - 追加到列表列表中的列表并更新列表列表 return
Haskell - Append to a list inside a list of lists and return the lists of lists updated
我花了数小时寻找将 [[a]]
操纵为 [[a]]
的方法,我认为这将是解决我的问题的最佳方法。问题包括将 a
附加到 [a]
和 returning [[a]]
以及新的更改。
例如:xs = [[a],[b],[c]]
和 y = d
.
我想将 y
附加到 xs!!0
。我不能使用 xs!!0 ++ y
因为它会 return 只是 [a,d]
,我知道这是因为 Haskell 的不变性。
我将如何着手将值附加到子列表并 returning 列表列表? - [[a,d],[b],[c]]
使用上面的示例来说明这一点。
let { xs = [[1]] ; y = 2 ; zs = [(xs!!0) ++ [y]] } in zs
是在 GHCi 提示符下尝试的一个示例。
它returns [[1,2]]
.
对于例如[[1],[2,3],[4]]
之类的,我们可以做到
appendToFirst :: [[a]] -> a -> [[a]]
appendToFirst (xs:r) y = (xs ++ [y]) : r
这样
> appendToFirst [[1],[2,3],[4]] 0
[[1,0],[2,3],[4]]
等号左边的(xs:r)
是一个模式.
等号右边( (...) : r)
中的(:)
是“cons
”操作,数据构造函数,(:) :: t -> [t] -> [t]
.
xs
绑定到输入列表的“头部”,即它的第一个元素,并且 r
绑定到输入列表的其余部分,在模式中;因此 xs
的值用于创建列表的更新版本,第一个子列表通过在其末尾附加一个值来更改,而 r
保持原样。
xs ++ [y]
创建一个 new 实体,新列表,而 xs
和 y
继续引用它们原来的旧值定义为。由于 Haskell 的值和变量是不可变的,正如您确实提到的那样。
编辑:如果你想在某个子列表的末尾添加新元素在中间,而不是如图所示的第一个上面,这可以用例如完成splitAt
函数,喜欢
appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y xs =
let
(a,b) = splitAt i xs
in
init a ++ [last a ++ [y]] ++ b
尝试一下:
> appendInTheMiddle 2 0 [[1],[2],[3],[4]]
[[1],[2,0],[3],[4]]
如果需要基于 0 的代码,则添加错误处理、边界检查和调整索引(顺便说一下,这将导致更简单、更快的代码),留作 reader.
在语法上,这可以通过“视图模式”进行简化,如
{-# LANGUAGE ViewPatterns #-}
appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y (splitAt i -> (a,b)) =
init a ++ [last a ++ [y]] ++ b
我花了数小时寻找将 [[a]]
操纵为 [[a]]
的方法,我认为这将是解决我的问题的最佳方法。问题包括将 a
附加到 [a]
和 returning [[a]]
以及新的更改。
例如:xs = [[a],[b],[c]]
和 y = d
.
我想将 y
附加到 xs!!0
。我不能使用 xs!!0 ++ y
因为它会 return 只是 [a,d]
,我知道这是因为 Haskell 的不变性。
我将如何着手将值附加到子列表并 returning 列表列表? - [[a,d],[b],[c]]
使用上面的示例来说明这一点。
let { xs = [[1]] ; y = 2 ; zs = [(xs!!0) ++ [y]] } in zs
是在 GHCi 提示符下尝试的一个示例。
它returns [[1,2]]
.
对于例如[[1],[2,3],[4]]
之类的,我们可以做到
appendToFirst :: [[a]] -> a -> [[a]]
appendToFirst (xs:r) y = (xs ++ [y]) : r
这样
> appendToFirst [[1],[2,3],[4]] 0
[[1,0],[2,3],[4]]
等号左边的(xs:r)
是一个模式.
等号右边( (...) : r)
中的(:)
是“cons
”操作,数据构造函数,(:) :: t -> [t] -> [t]
.
xs
绑定到输入列表的“头部”,即它的第一个元素,并且 r
绑定到输入列表的其余部分,在模式中;因此 xs
的值用于创建列表的更新版本,第一个子列表通过在其末尾附加一个值来更改,而 r
保持原样。
xs ++ [y]
创建一个 new 实体,新列表,而 xs
和 y
继续引用它们原来的旧值定义为。由于 Haskell 的值和变量是不可变的,正如您确实提到的那样。
编辑:如果你想在某个子列表的末尾添加新元素在中间,而不是如图所示的第一个上面,这可以用例如完成splitAt
函数,喜欢
appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y xs =
let
(a,b) = splitAt i xs
in
init a ++ [last a ++ [y]] ++ b
尝试一下:
> appendInTheMiddle 2 0 [[1],[2],[3],[4]]
[[1],[2,0],[3],[4]]
如果需要基于 0 的代码,则添加错误处理、边界检查和调整索引(顺便说一下,这将导致更简单、更快的代码),留作 reader.
在语法上,这可以通过“视图模式”进行简化,如
{-# LANGUAGE ViewPatterns #-}
appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y (splitAt i -> (a,b)) =
init a ++ [last a ++ [y]] ++ b