【问题标题】:Haskell. Sort by second element in the list of tuples哈斯克尔。按元组列表中的第二个元素排序
【发布时间】:2021-04-21 16:08:23
【问题描述】:

我有一个代码histogram,它显示了String中所有字符的个数。

histogram :: String -> [(Char, Int)]
histogram = foldr help [] where
    help x [] = [(x,1)] 
    help x ((y,z):yzs)
      | x == y = (y,z+1) : yzs 
      | otherwise = (y,z) : help x yzs

但是结果显示的顺序很混乱。我想按列表的第二个元素(即按数字)对结果进行排序。为此,我实现了ssort 代码,但它仅按第一个元素(字符)排序。

import Data.List (minimum, delete)

ssort :: Ord t => [t] -> [t]
ssort [] = []
ssort xs = x : ssort (remove x xs) where
     x = minimum xs

remove :: Eq a => a -> [a] -> [a]
remove _ [] = [] 
remove y (x:xs) | y == x = xs 
    | otherwise = x : remove y xs
 

输入: ssort [('a',1), ('g', 6), ('o',2), ('f',0)]

输出: [('a',1),('f',0),('g',6),('o',2)] (而不是 [( 'f',0),('a',1),('o',2),('g',6)])

我也不想使用任何其他内置函数,如 sort、sortOn 和 sortBy,我想实现自己的函数。

我怎样才能使它只比较第二个元素?

【问题讨论】:

  • 也许你想做的是定义你自己的minimum 函数,然后你可以专门处理对列表。类似minimumSnd :: Ord b => [(a,b)] -> (a,b)
  • @DDub 你甚至不需要额外的函数:你可以像minimumSnd = swap . minimum . fmap swap 这样实现它,这样很容易内联。
  • @bradm 的确如此,但发帖者并不是简单地询问如何获得正确答案,而是如何实现自己的功能以达到目标。我不是简单地给出答案,而是建议@Theresa 可能遵循的可能导致正确实施的路径。了解minimumssort 没有做发帖人想要做的事情的根本原因很重要,并且修复该实现是前进的方向。一旦理解,内联就很棒(事实上,整个事情都可以内联到sortOn snd)。

标签: list sorting haskell select histogram


【解决方案1】:

假设您也不想使用minimumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a

您可以利用元组的比较方式——首先是第一个元素,然后是第二个元素。因此,您可以先交换直方图的所有元素,然后排序,最后交换回来:

ssortOn2 :: (Ord t1, Ord t2) => [(t1, t2)] -> [(t1, t2)]
ssortOn2 = map swap . ssort . map swap 

(保持所有其他功能不变)

【讨论】:

    【解决方案2】:

    您可以提供自己对minimumBy的定义:

    minimumBy2 :: Ord t2 => [(t1, t2)] -> (t1, t2)
    minimumBy2 (h:t) = go h t where
      go x [] = x
      go x (h0:t0) = go (min x h0) t0
    minimumBy2 [] = error "minimumBy2: Empty list"
    

    然后您可以使用它来代替ssort 中的minimum,它应该可以工作。

    【讨论】:

      猜你喜欢
      • 2012-03-08
      • 2021-08-09
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 1970-01-01
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多