函数必须像这样:insertElemAt :: a -> [Int] -> [a] -> [a]
.
例子:
insertElemAt 0 [2,5,9] [1..10]
= [1, 0, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 10]
insertElemAt 0 [1,2,4,8] [0,1,0,0,1,1,0,1]
= [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1]
我只知道初学者Haskell(if
管道|
和递归),但我尽力解决这个问题,但它从未奏效。这是我最近的尝试:
insertElemAt x [0] ys = ys
insertElemAt x [1,2] ys = x:x:ys
insertElemAt x [] ys = ys
insertElemAt x xs [] = []
insertElemAt x (n:ns) (y:ys) = y:insertElemAt x (n-1:ns) ys
我也尝试过这样的东西,但这似乎很混乱,我认为第一个更好:
insertElemAt :: a -> [Int] -> [a]-> [a]
insertElemAt x [0] ys = ys
insertElemAt x [1,2] ys = x:x:ys
insertElemAt x (n:ns) (y:ys) = y:insertElemAt x (map reduc (n:ns)) ys
reduc (n:ns) = n-1 : reduc ns
也许我的模式不好?我试图用很多方式来写它们。
我还必须能够使用这个函数并在一个名为insertElemsAt (:: [(a, Int)] -> [a] -> [a])
的函数中使用它,它必须是上述函数的"通用"版本。所以我必须能够给出我想插入什么样的元素的位置。
由于我做不到第一个,所以我对这个更加迷茫。下面是示例。我不知道如何使用管道if
-s 和递归来做到这一点:
insertElemsAt (zip [0,1,1] [2,5,9]) [1..10]
= [1, 0, 2, 3, 1, 4, 5, 6, 1, 7, 8, 9, 10]
insertElemsAt (zip [0,1,1,1] [1,2,4,8]) [0,1,0,0,1,1,0,1]
= [0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1]
有人可以向我解释如何以最简单的方式做到这一点吗?提前感谢您的任何帮助!
假设索引列表是排序的,就像@AndyG所说的那样,如果你跟踪当前索引可能会有所帮助。因此,您可以实现如下函数:
insertElemAt :: a -> [Int] -> [a] -> [a]
insertElemAt x = go 0
where go _ [] ys = ys -- (1)
go i ns [] = … -- (2)
go i (n:ns) (y:ys) = … -- (3)
您需要填写…
部分的地方。
因此,这里的go
是一个使用递归插入元素的函数。基本情况 (1) 是要插入元素的索引列表用尽的地方,在这种情况下,我们可以返回列表本身。
如果列表本身已用尽,情况 (2),但仍有项目需要填写,您将需要创建一个列表,在其中重复x
您仍然需要插入的项目数。
最后一种情况(3)您必须检查索引i
与需要插入元素的第一个索引的比较n
。如果它相等,那么您将不得不插入元素x
并进行递归(您应该在其中调用go
)。如果索引大于当前索引,则生成元素y
,并在列表尾部递归并递增 acculator 索引。
你可以从你已经知道的东西开始:
insertElemAt 0 [
2, 5, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
= [1, 0, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 10]
这是一个完全有效的定义,即使对于一个非常具体的情况,它甚至会产生正确的结果,并且在其他任何地方都有所不同。
但是我们可以稍微概括一下,因为
insertElemAt _0 [
2, 5, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
= [1, _0, 2, 3, _0, 4, 5, 6, _0, 7, 8, 9, 10]
还有更多,
insertElemAt _0 [
2, 5, 9]
[a, b, c, d, e, f, g, h, i, j ]
= [a, _0, b, c, _0, d, e, f, _0, g, h, i, j ]
我们可以添加一些显然也必须成立的特殊情况,例如
insertElemAt _0 [
2, 5]
[a, b, c, d, e, f, g, h, i, j ]
= [a, _0, b, c, _0, d, e, f, g, h, i, j ]
和
insertElemAt _0 [
2]
[a, b, c, d, e, f, g, h, i, j ]
= [a, _0, b, c, d, e, f, g, h, i, j ]
甚至
insertElemAt _0 [
]
[a, b, c, d, e, f, g, h, i, j ]
= [a, b, c, d, e, f, g, h, i, j ]
我们可以进一步概括这一点,如
insertElemAt _0 [] xs
= xs
很明显,
insertElemAt _0 [
2]
[a, b, c, d, e, f, g, h, i, j ]
=
a : insertElemAt _0 [
1]
[b, c, d, e, f, g, h, i, j ]
和
insertElemAt _0 [
2, 5]
[a, b, c, d, e, f, g, h, i, j ]
=
a : insertElemAt _0 [
1, 4]
[b, c, d, e, f, g, h, i, j ]
总的来说
insertElemAt _0 (i:is) (x:xs)
| i > 1 = x : insertElemAt _0 (minus1 (i:is)) xs
必须成立,那么我们为什么不把它也作为我们定义的一部分;
-- minus1 is = [i-1 | i <- is]
minus1 [] = _____
minus1 (i:is) = ( ____ - 1) : ______ is
(填空)。所以对于i==1
的情况,
insertElemAt _0 (i:is) (x:xs)
| i == 1 = x : _0 : insertElemAt _0 (minus1 (_____)) xs
-- or is it
-- _0 : x : ........ ?
所以你已经走到了一半。剩下要做的就是添加几个边缘情况,你就完成了。
现在它不会是最有效的版本,因为它会反复从索引列表的每个成员中减去1
;你可以通过添加一个新的辅助参数来简化这部分,这将消除从索引列表的每个元素中减去的需要,并用一个加法替换它,向上计数而不是向下倒计时。若要使用该附加参数,必须定义并使用辅助的嵌套函数定义。