【问题标题】:Haskell - Remove n smallest elements in a list of tuplesHaskell - 删除元组列表中的 n 个最小元素
【发布时间】:2022-01-18 14:45:36
【问题描述】:

我有以下代码,它采用 int 值并删除列表中的前 n 个元素。

removeEle :: Int -> [a] -> [a]
removeEle n xs
    | ((n <= 0) || null xs) = xs
    | otherwise = removeEle (n-1) (tail xs)

我将如何附加它,以便它通过第二个元素在元组列表上起作用?等等

[(String1, 50)], [(String2, 600)], [(String3, 10)]

【问题讨论】:

    标签: list haskell tuples


    【解决方案1】:

    您无法修改当前解决方案以删除第一个n 最小元素。为了能够移除第一个最小的n,您需要对整个列表进行总排序,以便确定哪些元素在n 最小区间内。

    一个简单的解决方案是对列表进行排序并删除第一个 n 元素。但是,此解决方案不会保留原始顺序。

    使用来自Data.ListsoryBydrop,您可以执行以下操作:

    removeNSmallest :: Ord a => Int -> [(String, a)] -> [(String, a)]
    removeNSmallest n xs = drop n $ sortBy (\(_, a) (_, b) -> compare a b) xs
    

    正如@Micha Wiedenmann 指出的,您可以使用sortBy (comparing snd) 对元组进行排序。

    一个小测试:

    λ> removeNSmallest 1 [("String1", 50), ("String2", 600), ("String3", 10)]
    [("String1",50),("String2",600)]
    

    为了保留原始顺序,一种解决方案是为元组的第二个元素创建一个单独的有序列表。然后遍历原始列表,对于有序列表中的每个元素,从原始列表中删除一个。

    如果您使用 drop 编写删除列表前 n 个元素的原始解决方案,则该解决方案的可读性会更高:

    removeEle :: Int -> [a] -> [a]
    removeEle n xs = drop n xs
    

    或者如果你想使用显式递归:

    removeEle :: Int -> [a] -> [a]
    removeEle _ [] = []
    removeEle 0 xs = xs
    removeEle n x:xs = removeEle (n-1) xs
    

    【讨论】:

    • 你为什么要排序?如果你正在排序,sortBy (comparing snd).
    • 他的代码处理 removeEle (-1) [1..] 的方式也与您的版本不同。
    • 我不认为他们的removeEle 实现非常干净和惯用,所以我改变了它。关于排序:删除第 n 个最小的元素需要某种类型的排序,否则我们会变得非常低效。我同意这会改变原始列表的顺序,尽管根据要求这可能是不可接受的。对于这种情况,我添加了我们如何在仍然排序的同时针对这种情况修改此解决方案。 @MichaWiedenmann
    • 谢谢。我现在看到标题说“最小”,但第一句和示例没有。
    • 当然 :D 一开始我也对此感到困惑。
    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多