如何删除haskell中列表中的第二大元素?

时间:2018-03-12 09:37:26

标签: haskell

我创建了一个删除第一个最小元素的程序,但我不知道如何做第二大元素:

withoutBiggest (x:xs) =
   withoutBiggestImpl (biggest x xs) [] (x:xs)
     where
       biggest :: (Ord a) => a -> [a] -> a
       biggest big [] = big
       biggest big (x:xs) =
         if x < big then
           biggest x xs
         else
           biggest big xs
       withoutBiggestImpl :: (Eq a) => a -> [a] -> [a] -> [a]
       withoutBiggestImpl big before (x:xs) =
         if big == x then
           before ++ xs
         else
             withoutBiggestImpl big (before ++ [x]) xs

5 个答案:

答案 0 :(得分:1)

可能性,肯定不是最好的。

import Data.Permute (rank)

x = [4,2,3]
ranks = rank (length x) x -- this gives [2,0,1]; that means 3 (index 1) is the second smallest

然后:

 [x !! i | i <- [0 .. length x -1], i /= 1]

嗯..不是很酷,让我花点时间思考更好的事情,我会编辑我的帖子。

修改

此外我以前的解决方案是错误的。这个应该是正确的,但同样不是最好的:

import Data.Permute (rank, elems, inverse)

ranks = elems $ rank (length x) x
iranks = elems $ inverse $ rank (length x) x

>>> [x !! (iranks !! i) | i <- filter (/=1) ranks]
[4,2]

一个优点是,我认为这保留了列表的顺序。

答案 1 :(得分:1)

这是一个简单的解决方案。

Prelude> let list = [10,20,100,50,40,80]
Prelude> let secondLargest = maximum $ filter (/= (maximum list)) list
Prelude> let result = filter (/= secondLargest) list
Prelude> result
[10,20,100,50,40]
Prelude>

答案 2 :(得分:1)

这是一个从列表中删除n个最小元素的解决方案:

import Data.List

deleteN :: Int -> [a] -> [a]
deleteN _ []     = []
deleteN i (a:as)
   | i == 0    = as
   | otherwise = a : deleteN (i-1) as

ntails :: Int -> [a] -> [(a, Int)] -> [a]
ntails 0 l _ = l
ntails n l s = ntails (n-1) (deleteN (snd $ head s) l) (tail s)

removeNSmallest :: Ord a => Int -> [a] -> [a]
removeNSmallest n l = ntails n l $ sort $ zip l [0..]

编辑:

如果您只想删除第二个最小元素:

deleteN :: Int -> [a] -> [a]
deleteN _ []     = []
deleteN i (a:as)
   | i == 0    = as
   | otherwise = a : deleteN (i-1) as

remove2 :: [a] -> [(a, Int)] -> [a]
remove2 [] _  = []
remove2 [a] _ = []
remove2 l s = deleteN (snd $ head $ tail s) l

remove2Smallest :: Ord a => [a] -> [a]
remove2Smallest l = remove2 l $ sort $ zip l [0..]

答案 3 :(得分:0)

目前尚不清楚OP是否正在寻找最大的(如名称withoutBiggest所暗示的)或什么。在这种情况下,一种解决方案是合并filter :: (a->Bool) -> [a] -> [a]中的maximum :: Ord a => [a] -> aPrelude函数。

withoutBiggest l = filter (/= maximum l) l

答案 4 :(得分:0)

您可以先删除最大的元素,然后对其进行过滤:

withoutBiggest :: Ord a => [a] -> [a]
withoutBiggest [] = []
withoutBiggest xs = filter (/= maximum xs) xs

然后你可以用同样的方式删除第二大元素:

withoutSecondBiggest :: Ord a => [a] -> [a]
withoutSecondBiggest xs =
  case withoutBiggest xs of
    [] -> xs
    rest -> filter (/= maximum rest) xs

做出的假设:

  • 您希望每次出现第二大元素都被删除。
  • 当列表中有零个/一个元素时,不存在第二个元素,因此不存在第二大元素。拥有没有元素的列表就相当于拥有列表。
  • 当列表仅包含相当于maximum xs的值时,即使可能总共有两个或更多元素,也没有第二大元素。
  • Ord类型类实例意味着总排序。否则,您可能有多个不相等的最大值;否则哪一个被选为最大的,而第二大的则没有明确定义。