我有[(X, (R, R))]
類型(元組的列表,其中,2次元件是一個元組過),其中X
和R
是一些任意類型的列表,以及R
是類型類Ord
的成員。這樣的清單的例子:[(0, (0,1)), (1, (1,1)), (2, (0,0)), (3, (1,0))]
。想象一下,我想查找這個列表中的所有元素,其中第二個元素的第一個元素(即內部元組的左側元素)是最大的。但我不想只有一個這樣的元素,我想要所有元素,其中一個內部元素的左側元素是最大的。所以我的函數,在上面的列表中調用,應該返回[(1, (1,1)), (3, (1,0))]
。 maximumBy
不起作用,因爲它只會返回一個元素。所以我寫的maximumBy
的變化,其返回多個最大值:
maximumByM :: (a -> a -> Ordering) -> [a] -> [a]
maximumByM c (x:xs) = maximumByM' c xs [x]
where maximumByM' _ [] acc = acc
maximumByM' c (x:xs) [email protected](a:_) = case x `c` a of
LT -> maximumByM' c xs acc
EQ -> maximumByM' c xs (x:acc)
GT -> maximumByM' c xs [x]
後綴-M的意思是「多」。這多值函數返回(根據自定義比較)是最大所有值的列表:
maximumByM compare [1,2,3] -- [3]
maximumByM compare [1,2,3,1,2,3] -- [3,3]
maximumByM (comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(6,2),(6,1)]
maximumByM (comparing snd) [(5,1), (5,2), (6,1), (6,2)] -- [(6,2),(5,2)]
要實現minimumByM
所有你需要做的是flip比較,因爲compare 1 2 == (flip compare) 2 1
:
maximumByM (flip $ comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(5,2),(5,1)]
-- the below 2 are equivalent due to Haskell's currying
minimumByM = maximumByM . flip
minimumByM c xs = maximumByM (flip c) xs
不幸的是maximumByM
以相反的順序返回列表。我可以在代碼中添加reverse
,但是這種雙重工作?顯式遞歸?爲什麼使用right fold沒有實現相同的功能:
maximumByM :: (a -> a -> Ordering) -> [a] -> [a]
maximumByM _ [] = []
maximumByM c (x:xs) = foldr f [x] xs
where f = (\e [email protected](a:_) -> case c e a of
LT -> acc
EQ -> e:acc
GT -> [e])
現在它返回相同的順序列表,元素在最初的名單中發現:
maximumByM (comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(6,1),(6,2)]
當然,你可以使用Boyd Stephen Smith Jr的方法,結合groupBy
和sortBy
(sortBy
需要flip
因爲它按從小到大):
maximumByM :: (a -> a -> Ordering) -> [a] -> [a]
maximumByM _ [] = []
maximumByM c xs = head $ groupBy ((==EQ) .: c) $ sortBy (flip c) xs
where (.:) = (.).(.) -- x .: y = \a b -> x(y a b)
你不需要扭轉名單,因爲sortBy
將保留元素的它認爲相等的順序:
maximumByM (comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(6,1),(6,2)]
我沒有看到一個問題。 –
你嘗試過'Data.List.maximumBy'嗎? – bheklilr
@Rhymoid我編輯了這個問題,我認爲它沒有明確地需要一個問題。 – user3870660