2014-07-23 93 views
0

userDatabase是由諸如(id,username,password)之類的元組組成的列表。我如何通過使用最大ID來過濾列表?我現在所擁有的是什麼都不做,但我認爲我在某種情況下加入了它。通過最大元素過濾元組列表

newUser :: UserDatabase -> UserDatabase 
newUser usrdb = filter (\(usrid,_,_) -> usrid == (maximum [x | (x, _, _) <- userdb])) userdb 

在此先感謝!

+3

我沒有看到一個問題。 –

+1

你嘗試過'Data.List.maximumBy'嗎? – bheklilr

+0

@Rhymoid我編輯了這個問題,我認爲它沒有明確地需要一個問題。 – user3870660

回答

3

所有的usrid值是不同的?在這種情況下,只有最大的一個,所以你可以這樣做:

type User = (Int, String, String) 
type UserDatabase = [User] 

fst3 (x, _y, _z) = x 

userHigh :: UserDatabase -> User 
userHigh = maximumBy (comparing fst3) 

如果ID是不顯着,你可能有一些關係,所以你要返回一個列表

usersHigh :: UserDatabase -> [User] 
usersHigh = concat . take 1 
      . groupBy (on (==) fst3) 
      . sortBy (flip $ comparing fst3) 
+0

非常感謝!剛剛做了一個簡單的測試,它的工作。我會在明天繼續努力,但它看起來很棒! – user3870660

1

未經檢驗的,但應該讓你去:

maximumBy :: Ord b => (a -> b) -> [a] -> Maybe a 
maximumBy extract [] = Nothing 
maximumBy extract (x:xs) = go x xs 
    where go candidate [] = Just candidate 
      go candidate (x:xs) 
       | extract x > extract candidate = go x xs 
       | otherwise = go candidate xs 

編輯:哦,bhelkir指出這個功能已經存在於庫中。不管怎樣,有幾點:

  1. 如果你想從列表中得到的只是一個項目,它不是一個filter操作,它更像是一個findminimum/maximum操作。
  2. 你會使用這種方式是這樣的:maximumBy (\(usrid,_,_) -> usrid) usersmaximumBy的第一個參數是一個從列表元素中提取比較字段的函數。
+0

我已經嘗試過與最大的混淆,而且我得到一個奇怪的錯誤:發生檢查:無法構造無限類型: t0 =(t0,t1,t2) - >排序 – user3870660

+0

@ user3870660該評論聽起來像是可能另一個問題,關於類型檢查。 –

+0

@BoydStephenSmithJr。要注意我刪除了類型簽名以獲得該錯誤,並且在使用'newUser :: UserDatabase - > User'時,我得到:'無法匹配Int類型與用戶 - >排序' 預期類型:用戶 - >排序 實際類型:UserID' – user3870660

0

我有[(X, (R, R))]類型(元組的列表,其中,2次元件是一個元組過),其中XR是一些任意類型的列表,以及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的方法,結合groupBysortBysortBy需要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)]