【问题标题】:Turn these haskell Int lists into a different one将这些 haskell Int 列表变成不同的列表
【发布时间】:2010-09-27 14:19:10
【问题描述】:

我有以下 Int 列表:

t1 = [1000, 1001, 1002, 1003, 1004]
t2 = [2000, 2001, 2002]
t3 = [3000, 3001, 3002, 3003]

列表大小是可变的,它们不只是像这个例子中的 3。它们可以有 1 个或更多元素。然后我有这个:

tAll = [t1, t2, t3]

我需要一个将 tAll 变成这样的函数:

[[1, 1000, 2000, 3000],
[2, 1001, 2001, 3001],
[3, 1002, 2002, 3002],
[4, 1003, 0, 3003], 
[5, 1004, 0, 0]]

有没有简单的方法可以做到这一点?

编辑: 对不起,我匆忙发布了这个,这不是我想要的。我更新了上面的代码...

【问题讨论】:

    标签: haskell list


    【解决方案1】:

    如果您仍然感兴趣,这里有一个适合您的单线:

    zipWith (:) [1..] $ take (maximum $ map length tAll) 
                             (transpose (map (++repeat 0) tAll))
    

    edit:好的,最好用两行写:)

    【讨论】:

    • 非常好,+1。这是最好的解决方案!与我在之前的评论中所说的相反,这在每个列表的长度和列表的数量上都是线性的 :-)
    【解决方案2】:

    嗯,这是 Haskell 初学者的编写方式,但由于它进行显式递归,因此可能有更好的方式。 :-)

    head0 [] = 0
    head0 xs = head xs
    
    tail0 [] = []
    tail0 xs = tail xs
    
    nreorder n ts
      | all null ts = []
      | otherwise   = (n : map head0 ts) : nreorder (n+1) (map tail0 ts)
    

    nreorder 1 tAll 打印出你想要的列表。您可以通过执行以下操作来避免这些索引:

    reorder ts
      | all null ts = []
      | otherwise   = (map head0 ts) : reorder (map tail0 ts)
    

    这样reorder tAll = [[1000,2000,3000],[1001,2001,3001],[1002,2002,3002],[1003,0,3003],[1004,0,0]],和(稍微清理了感谢mattiast):

    nreorder ts = zipWith (:) [1..] (reorder tAll)
    

    以便nreorder tAll 打印您想要的列表。

    【讨论】:

    • 我觉得它很混乱......没有额外的头/尾功能和/或没有“all null ts = []”的东西没有办法吗?
    • 额外的头/尾函数是表达你想用空列表做什么的最简单方法。如果您想使用 Haskell,请习惯辅助功能。 “all null ts”对于处理任意数量的输入列表很有用,而不是恰好 2、3 或 42 个列表...
    • all null ts 表示是否“ts 中的所有列表都为空”。想想你在最后一步需要做什么,在“nreorder 4 [[1003,1004],[],[3003]]”和“nreorder 5 [[1004],[],[]]”之后来到“nreorder 6 [[],[],[]]”。
    • 呃,你不应该把它读作“all null ts = []”——也许你需要熟悉守卫语法? en.wikipedia.org/wiki/Guard_%28computing%29
    【解决方案3】:

    闻起来像作业,所以我不会给出代码,但一些提示:
    - 结果列表的长度都相同,这是列表的最大值。找到最大值并用零填充所有其他列表(使用惰性可以用无限的零列表填充所有列表)。
    - 获得一个中间版本,它只打印您最终答案的第一列...
    - 当你有这个工作时,得到第二列....其余的应该是肉汁。

    编辑:评论表明这不是家庭作业,所以:

    列表 = [[1000, 1001, 1002, 1003, 1004],[2000, 2001, 2002],[3000, 3001, 3002, 3003]]

    main = do mapM_ (putStrLn.show) (旋转列表) 旋转列表 = [(i+1):map (!!i) 填充列表 | i

    【讨论】:

    • 哎呀,我希望我没有给出家庭作业的答案......但考虑到他的第一个版本的问题是完全不同的,而且他之前的问题似乎是关于 Html 的东西,这更有可能是“现实生活”中的问题。
    • 这仍然是关于 Html 的东西,我只是做了一个通用的示例以便更容易理解,稍后我会对其进行调整。实际上这是我明天必须提交的一个项目,但这个问题特别是我想做的事情,它不是任何请求功能的一部分。
    • 不错。顺便说一句,这需要多少时间?似乎(因为 !! 和 ++)某些东西是二次方的,它可以是线性的,但我不确定面对懒惰的评估如何推理。
    • 是(!!)线性时间还是常数时间?我可以看到它是线性的,逐步通过列表,但是,通过装箱,它可能是 const-just mult 来获得偏移量。无论如何,一些快速计时显示旋转比 nreorder 快 5 倍(在 ghc 6.8.2 下,5 秒对 1 秒(采用 10e5 列表))。我可能会对其进行分析。
    • (!!) 是线性的。但我不知道 ghc 是否可以在总线性时间内计算出所有连续的 (!!)。呃......你的意思是“更慢”吗?似乎rotate在列表数量上是线性的,但在长度上是二次的:对于长度为n的m个列表,O(mn^2),而nreorder是O(mn)。因为(++)我猜。
    【解决方案4】:

    zip3 会将 3 个列表变成一个三元组列表。如果你想要长度为三个的列表,你可以使用zipWith3 (\a b c -> [a,b,c])

    如果您想要在细节上有所不同(如更新后的请求),您必须自己动手。我想说,把你的终止条件放在第一位,然后处理一般情况。您应该有两个辅助函数——一个以您想要的方式修复值(例如,“head_or_zero”),另一个用于处理已终止的输入列表(例如,“tail_or_nil”):

    
    fix _ [] [] [] = []
    fix i as bs cs = [i, hoz as, hoz bs, hoz cs]:fix (i+1) (ton as) (ton bs) (ton cs) where
        hoz [] = 0
        hoz x:xs = x
        ton [] = []
        ton x:xs = xs
    

    【讨论】:

      猜你喜欢
      • 2012-02-05
      • 1970-01-01
      • 2015-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      • 2015-09-08
      • 2011-05-18
      相关资源
      最近更新 更多