计算haskell中列表中的反转次数

时间:2014-08-04 08:48:45

标签: haskell

我们如何在Haskell中的列表中计算反演?  例如。 [1, 2, 3, 1]xi > xj其中i < j是反转的条件。在给定的例子中,它将是3。

我尝试了以下代码:

module Inversion where

inv :: Ord a => [a] -> [(a, a)]
inv [] = []
inv xs = [(a, b) | a <- xs, b <- tail xs, a > b]

我甚至尝试用尾巴压缩它然后得到它们。

5 个答案:

答案 0 :(得分:4)

import Data.List

inv :: Ord a => [a] -> [(a, a)]
inv xs = [(a,b) | (a:bs) <- tails xs, b <- bs, a > b]

答案 1 :(得分:1)

这是一个接近你已经得到的天真实现:

inv :: Ord a => [a] -> [(a, a)]
inv [] = []
inv xs = [(a, b) | b <- xs', a > b] ++ inv xs'
    where xs' = tail xs
          a = head xs

首先想到的是:将第一个元素与列表中的其他元素进行比较,然后对列表的其余部分进行相同的操作。

你的例子:

*Main> inv [1,2,3,1]
[(2,1),(3,1)]

答案 2 :(得分:0)

这似乎对我有用:

inv lst = filter nonOrdPair $ zip lst (tail lst)
        where nonOrdPair (a,b) = a > b
你的例子中的

给出了

Prelude> inv [1, 2, 3, 1]
[(3,1)]

如果您只需要第一个元素,则可以使用map fst获取它。

答案 3 :(得分:0)

在这种情况下,您无法使用ziptail。这将导致仅比较连续对,您需要所有对。因此,如果列出了(x:xs),则需要检查xs是否小于x

import Data.Maybe (mapMaybe)

checkInv :: Ord a => a -> a -> Maybe (a,a)
checkInv x y = if x <= y then Nothing
                         else Just (x, y)

inv :: Ord a => [a] -> [(a,a)]    
inv []     = []
inv (x:xs) = mapMaybe (checkInv x) xs ++ inv xs
> inv [1,2,3,1]
[(2,1), (3,1)]

答案 4 :(得分:0)

只是为了解决这个问题:

inv :: Ord a => [a] -> [(a,a)]
inv [x] = [] :: [(x,x)]
inv xs = foldl (\acc x -> if (head xs) > x then (head xs, x) : acc else acc) [] xs

压缩然后过滤这些对并不是一个坏主意,但你必须考虑所有这些对才能起作用:

inv xs = filter (\(a, b) -> a > b) $ allPairs xs
  where
    allPairs xs = allPairsHelp xs (tail xs)
      where
        allPairsHelp xs [] = []
        allPairsHelp xs ys = zip xs ys ++ allPairsHelp xs (tail ys)