【问题标题】:Haskell combine the elements of 2 lists at different index'sHaskell 将不同索引处的 2 个列表的元素组合在一起
【发布时间】:2021-05-09 01:01:46
【问题描述】:

对于这个糟糕的标题,我不太清楚如何用语言来描述它,但这就是我的意思。如果您知道更好的表达方式,请告诉我。

假设我有 2 个长度相同的列表。

[a, b, c] [x, y, z]

我要创建列表

[[a, y, z], [b, x, z], [c, x, y]]

基本上对于 list1 的每个元素,我希望 list2 中第一个元素的不同索引处的 2 个元素。

所以对于索引 0 处的“a”,其他 2 个是索引 1 处的“y”和索引 2 处的“z”。

我很确定我知道如何使用索引来做到这一点,但是,我知道这不是很有效,我想看看是否有更实用的解决方案。

谢谢。

【问题讨论】:

    标签: list haskell functional-programming combinations


    【解决方案1】:

    您没有描述任何边缘情况,但您可以通过以下方式获得您正在寻找的基本行为:

    import Data.List (inits, tails)
    
    combine :: [a] -> [a] -> [[a]]
    combine xs ys = zipWith3 go xs (tails ys) (inits ys)
      where
        go a (_:xs) ys = a:ys ++ xs
        go _ _ _ = []
    

    关键是tails返回其列表的连续后缀,从完整列表开始,inits返回连续前缀,从空列表开始。

    【讨论】:

    • 这适用于长度大于 3 的列表吗?
    • 当然!如果您担心zipWith3 中的“3”,那与列表的长度无关。正如我所说,有很多你没有指定的边缘情况,例如,当列表长度不同时会发生什么?这个函数不会出错或任何东西,但你可以用它来获得你想要的行为。
    • 对于这个函数,当我使用它时,我通过它的两个数组是彼此的一种变体,所以它们总是相同的大小,如果它们之前是空的,我会发现
    【解决方案2】:

    我会用拉链来做。这是我在很多项目中编写的一个函数,我已经记住了它:

    zippers :: [a] -> [([a], a, [a])]
    zippers = go [] where
        go b [] = []
        go b (h:e) = (b, h, e) : go (h:b) e
    

    (这实际上返回的信息比我们在此应用程序技术上所需的信息要多。但它是一般形式——在许多情况下很有用,其中仅返回前缀/后缀对并省略当前焦点的受限版本有时会还不够。)

    有了这个工具,我们只需zip(不同类型的拉链!)将一个列表中的值与另一个列表的拉链一起。

    combine :: [a] -> [a] -> [[a]]
    combine xs ys = zipWith (\x (b, h, e) -> reverse b ++ [x] ++ e) xs (zippers ys)
    

    在 ghci 中尝试一下:

    > combine "abc" "xyz"
    ["ayz","xbz","xyc"]
    

    【讨论】:

    • 列表长度大于3的情况下是否有效
    • @SamTaaghol 试试看!
    【解决方案3】:

    你可以试试这个:

    \xs ys -> zipWith3 (((++) .) . (:)) xs (init $ inits ys) (tail $ tails ys)
    

    【讨论】:

      猜你喜欢
      • 2020-01-27
      • 1970-01-01
      • 2015-08-26
      • 2021-04-21
      • 2021-08-10
      • 2011-09-27
      • 1970-01-01
      • 1970-01-01
      • 2013-04-17
      相关资源
      最近更新 更多