【问题标题】:Insert an element into a list, to the given indexes, in Haskell在 Haskell 中将元素插入到给定索引的列表中
【发布时间】:2020-08-05 08:54:06
【问题描述】:

函数必须是这样的: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]

谁能以最简单的方式向我解释如何做到这一点?提前感谢您的帮助!

【问题讨论】:

  • 我认为你最好使用一个累加器来跟踪当前索引。此外,您应该始终查看要插入的索引列表的头部。像insertElementAt x [1,2] 这样的模式很可能“太具体”。这里。我认为您的第一个模式insertElemAt x [0] 在语义上也是不正确的,因为这里的结果应该是x:ys
  • 这里一个不言而喻的前提是索引列表是排序的

标签: list haskell recursion insert guard-clause


【解决方案1】:

假设索引列表已排序,例如@AndyG says,如果您跟踪当前索引可能会有所帮助。因此,您可以实现如下功能:

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,并在列表尾部进行递归并增加累加器索引。

【讨论】:

    【解决方案2】:

    你可以从你已经知道的开始:

    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
    

    必须成立,所以我们为什么不把 it 作为我们定义的一部分;与

    -- 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;您可以通过添加一个新的辅助参数来简化这部分,这将否定从索引列表的每个元素中减去的需要,并用一个加法替换它,向上计数而不是向下计数。要使用该附加参数,您必须定义和使用辅助的嵌套函数定义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-17
      • 2010-12-02
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-11
      • 2018-11-24
      相关资源
      最近更新 更多