我想首先按字符串的长度对String
的列表进行排序,如果长度相同则应该按词法排序。我以为我可以使用Data.List
库并编写我自己的比较函数来做到这一点。因此compare函数应该以{{1}}列表作为参数,并比较所有元素(String
s)。 String
s的比较函数看起来像这样
String
如何使用这样的函数处理所有列表元素?
答案 0 :(得分:5)
首先,您的cmp
函数无法处理长度相等的情况:您需要添加它。否则,您将收到运行时模式匹配错误:
comp a b
| length a > length b = GT
| length a < length b = LT
| otherwise = undefined -- TODO
另外,请注意,此实现有时会计算两次长度,但GHC很可能会自行优化这一长度,而且我们以后会更加基本地解决这个问题。
然后,一旦您修复了comp
,您需要做的就是将其与您想要排序的字符串列表一起传递给Data.List.sortBy
。下面提供了类似的实现(<$>
是fmap
的运算符别名,其作用与列表上map
的作用相同。)
然而,通过将每个元素映射到一对,其中第一个成员是原始字符串,并且首先计算列表中所有元素的长度,这是一个更好的解决方案。第二个是它的长度。然后使用修改后的comp
函数,该函数需要2对而不是2个字符串,否则其行为与原始comp
的行为相同。但是,您需要将中间列表映射回仅包含字符串(这是fst <$>
的用途,这相当于map fst
但是,再次使用,IMO更好看,{ {1}}操作员)。
所以有些天真的解决方案将是:
<$>
和效率更高,如左下所示,将是:
sortByLenOrLex :: [String] -> [String]
sortByLenOrLex as = sortBy cmp as where
cmp a b | n > m = GT
| n < m = LT
| otherwise = compare a b
where n = length a
m = length b
首先使用每个元素的长度修改列表,以避免重复,昂贵的sortByLenOrLex' :: [String] -> [String]
sortByLenOrLex' as = fst <$> sortBy cmp (addLen <$> as) where
cmp (a,n) (b,m) | n > m = GT
| n < m = LT
| otherwise = compare a b
addLen x = (x, length x)
调用。
编辑:请参阅chi's answer以获得更好的此算法实施方法!
<强>此外:强>
您可以通过对 length
列表的列表进行操作来使您的功能变得通用:
Ord
这会给你:
sortByLenOrLex'' :: Ord a => [[a]] -> [[a]]
sortByLenOrLex'' as = fst <$> sortBy cmp (addLen <$> as) where
cmp (a,n) (b,m) | n > m = GT
| n < m = LT
| otherwise = compare a b
addLen x = (x, length x)
...如果您想让它尽可能通用,您可以对{{1>} *Main> sortByLenOrLex'' [[1,2], [1,3], [1,2,3]]
[[1,2],[1,3],[1,2,3]]
的列表进行排序:
Foldable
这会给你:
Ord
答案 1 :(得分:3)