【问题标题】:Haskell - check whether a 2D list has the same number of rows as columnsHaskell - 检查二维列表的行数是否与列数相同
【发布时间】:2013-05-01 06:07:05
【问题描述】:

我在 Haskell 中有一个二维列表 [[Int]],我想检查两件事:

  1. 列表的列数是否相同
  2. 行的元素数量是否相同

例如:

[[1,2,3], [1,55,9]] 的行数与列数相同——此处为 2——每行的元素数相同,即 3。

但是

[[1,2], [1,55], [4,7]] 在每行中具有相同数量的元素,尽管它的行数和列数不相等,即 3r 2c。

又一个例子:

[[1,2], [1,55], [4,7,8]] 的行数与列数都不相同,每行的元素数也不相同。

其实第一步包括第二步,对吗?

我的尝试:

所以到目前为止我尝试的是这样的:

listIsEqual :: [[Int]] -> Bool
listIsEqual myList = (all (\x -> length x == (length myList)) )

现在我收到以下错误消息:

Couldn't match expected type `Bool' with actual type `[a0] -> Bool'
In the return type of a call of `all'
Probable cause: `all' is applied to too few arguments
In the expression: (all (\ x -> length x == (length myList)))
In an equation for `listIsEqual':
            listIsEqual myList = (all (\ x -> length x == (length myList)))

谁能告诉我问题出在哪里?

还有其他方法可以解决这个问题吗?

【问题讨论】:

  • 好吧,如果你的数据的形状是一个常规的多维数组,我认为你应该尝试使用数组类型而不是[[a]];这样,数据类型可以保证始终满足形状。 Look here.

标签: arrays list haskell equality


【解决方案1】:

对于第二个任务,您可以映射定义函数的每一行的长度(该行中的列数)

let columnLengths rows = map length rows
Prelude> columnLengths [[1,2], [1,55], [4,7,8]]
[2,2,3]

现在我们有了一个包含列长度的列表,我们必须检查它们是否都相等。 Data.List 中的函数 nub 从列表中删除重复项。

let columnsLengthEqual = (==) 1 . length . nub . columnLengths

或者一起

let columnsLengthEqual = (==) 1 . length . nub . map length

【讨论】:

  • 坦率地说我错过了任务的意图..他们不一样吗?我的意思是当我解决第一步时,我也已经解决了第二步。所以,对我来说,第二步是第一步的一部分。我错过了什么吗???
  • 不,你没有错过任何东西,我做到了:-)
【解决方案2】:

GHC 的错误消息并不总是最有帮助的,但在这种情况下它是正确的。

可能的原因:`all' 应用于太少的参数

确实,您忘记了all 的第二个参数:

listIsEqual myList = all (\x -> length x == length myList) myList
                                                           ^^^^^^

【讨论】:

  • 感谢两位的帮助。我现在在这个简短的函数listIsEqual myList = all (==(length myList)) (map length myList) 中解决了它。你看到任何关于它的问题吗?我也会测试您的解决方案并尽快提供反馈...
  • @John:这相当于我的解决方案。一般情况下,all p (map f xs) === all (p . f) xs.
  • 对不起,我以前没见过,因为它与我的第一次尝试非常相似,我以为你引用了我的话 ;-) 所以在我的第一个方法中,我忘记了第二个参数:- (
【解决方案3】:

尊重您的标准的矩阵是平方矩阵,然后检查 first 的行长度的平方是否等于元素的数量应该没问题。

isSquaredMatrix xs@(h:_)  = ((^2) . length $ h) == (length . concat $ xs) 
isSquaredMatrix _         =  True 

但正如 hammar 所指出的,这是不正确的,因为我们可以使用错误的输入获得积极的结果。

# isSquaredMatrix [[1,2,3],[4,5],[6,7,8,9]]
True -- But this is false  

@约翰,

当我们想要引用整个类型的同时我们已经分解它时,我们使用@ 进行模式匹配。一个例子应该可以让你更深入地了解,

通常我们可以使用模式匹配定义一个详尽的函数,如下所示。

actOnList []     = -- do something when we encounter an empty list
actOnList (x:xs) = -- do something with h, and do another stuff with xs  

例如,

actOnList [] = []
actOnList (x:xs) = 
    if (pred x)
    then x:xs
    else actOnList xs

我的函数在这里消费列表,直到满足谓词。
我们可以想象skipUntilMeetAChar

skipUntilMeetAChar :: [Char] -> Char -> [Char]
skipUntilMeetAChar []  c    = []
skipUntilMeetAChar (x:xs) c = 
    if (x==c)
    then x:xs
    else actOnList xs c

正如您看到的,当遇到字符时,我们希望返回列表,而不仅仅是尾部,然后我们需要使用头部x 和尾部xs 重建我们的列表。这可以使用@ 来克服。

skipUntilMeetAChar :: String -> Char -> String
skipUntilMeetAChar []  c    = []
skipUntilMeetAChar l@(x:xs) c = 
    if (x==c)
    then l 
    else actOnList xs c

现在,关于 ($) 运算符,这又是一些语法糖。
由于函数应用程序是左关联的,这导致我们广泛使用括号来重新排序函数的应用程序,如下例所示。

# f3 (f2 (f1 (f0 x)))

然后为了避免管理右括号的痛苦,引入了美元运算符$,然后我们之前的表达式就变成了。

# f3 $ f2 $ f1 $ f0 x

这绝对是更具可读性和最容易编写的。

注意该运算符定义如下。

($) :: (a -> b) -> a -> b  
f $ x = f x  

我建议您通过以下introduction material 了解更多信息。

【讨论】:

  • 这种方法会给你带来误报。例如,它为 [[1,2,3],[4,5],[6,7,8,9]] 返回 true。
  • 谢谢,这似乎也是一个不错的解决方案,但是我还不知道 @ 和 $ 的含义。我是新手 ;-)
  • @hammar 感谢提及。我将相应地更新答案,并借此机会向 John 介绍模式匹配和 ($) 运算符。
  • @zurgl 非常感谢您的帮助。由于我明天要为考试再做一项 Haskell 任务,所以明天放学后我会尽力理解你的解释。我最近的作业遇到了很大的麻烦,我在这里发布了stackoverflow.com/questions/16426680/… 如果你能帮助我,那将非常好,以便我明天通过考试。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2014-05-15
  • 2019-12-25
  • 2012-01-10
  • 1970-01-01
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 2019-12-06
相关资源
最近更新 更多