【问题标题】:Throwing away element in index,element tuples丢弃索引中的元素,元素元组
【发布时间】:2017-06-01 21:33:27
【问题描述】:

Haskell 新手,尝试构建一个 [[(Int, Int)]],其中每个元素都是其对应的网格位置,由另一个板 [[a]] 构建。因此,边长为 3 的正方形 [[a]] 将创建

[[(0, 0), (1, 0), (2, 0)]
,[(0, 1), (1, 1), (2, 1)]
,[(0, 2), (1, 2), (2, 2)]]

(最终我将使用map (map ...) 将其迭代为[[a]] -> (Int, Int) -> b 类型的函数以创建[[b]],所以如果我遗漏了一些更容易的东西,请告诉我!)

在 Python 中,我可能会执行以下操作:

[[(x,y) for (x,_) in enumerate(board[y])] for (y,_) in enumerate(board)]

也就是说,我会使用 enumerate 内置函数来构造 (index, element) 元组并丢弃元素。

我知道在 Haskell 中我可以做到:

[[(x,y) | x <- [0..length (board!!y)-1]] | y <- [0..length board-1]]

但是 Python (for foo in range(len(bar))) 中的那些结构有点反模式,并且非常不鼓励。在 Haskell 中也是这样吗?

如果我像编写 Python 一样编写 Haskell,我会这样做:

[[(x,y) | (x,_) <- zip [0..] (board!!y)] | (y,_) <- zip [0..] board]

这是不受欢迎的吗?

【问题讨论】:

  • 更一般地说:在 Python 中,如果它写得好且符合习惯,我们会谈论“Pythonic”。 “Haskellion”结构在这里有类似的术语吗?

标签: list haskell list-comprehension enumerate


【解决方案1】:

您最后的“像 Python 一样编写”建议几乎是好的,但是您不必要地丢弃了板上的行,然后使用 (!!) 重新创建它们。像这样写就可以了:

board :: [[Char]]
board = ["abc", "def", "ghi"]

board' :: [[(Int, Int)]]
board' = [[(x, y) | (x, _) <- zip [0..] row]
                  | (y, row) <- zip [0..] board]

【讨论】:

  • 这是完美的。不知道为什么我自己没有想到这个——谢谢!
【解决方案2】:

通常(!!) :: [a] -&gt; Int -&gt; a 并不是一个很好的运算符:它需要O(k) 时间来访问第k 个元素。对于你的小例子,这当然不是一个真正的问题,但它可以将一些算法从 O(n) 变成 O(n2).

通常在 Haskell 中,人们旨在通过编写可以迭代列表的巧妙算法来避免这种情况,而不是获取(随机)索引

在 Python 中你可以重写你的:

[[(x,y) for (x,_) in enumerate(board[y])] for (y,_) in enumerate(board)]

进入:

[[(x,y) for (x,_) in enumerate(<b>by</b>)] for (y,<b>by</b>) in enumerate(board)]

Haskell 中的等价物是:

[ [ (x,y) | (x,_) <- zip [0..] by ] | (y,by) <- zip [0..] board ]

或者我们可以通过首先在 Haskell 中引入 enumerate :: (Enum a, Num a) =&gt; [b] -&gt; [(a, b)] 函数来使代码更简洁:

enumerate :: (Enum a, Num a) => [b] -> [(a, b)]
enumerate = zip [0..]

然后写:

[ [ (x,y) | (x,_) <- enumerate by ] | (y,by) <- enumerate board ]

【讨论】:

    【解决方案3】:

    您的旁白似乎暗示您可能对以下函数感兴趣,有时称为mapWithIndex(例如in containers),有时称为imapin lens)。

    mapWithIndex :: (Int -> a -> b) -> [a] -> [b]
    mapWithIndex f = go 0
      where
        go !_i [] = []
        go i (x : xs) = f i x : go (i + 1) xs
    

    所以mapWithIndex (\i -&gt; mapWithIndex (\j y -&gt; (i,j,y))) 将获取一个列表并用其位置注释每个元素。当然,您可以执行任意计算,而不是注释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-17
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      相关资源
      最近更新 更多