11

リスト内の各要素の頻度をカウントするプログラムを書こうとしています。

    In: "aabbcabb"
    Out: [("a",3),("b",4),("c",1)]

次のリンクで私のコードを表示できます。http://codepad.org/nyIECIT2 このコードでは、一意の関数の出力は次のようになります。

     In: "aabbcabb"
     Out: "abc"

一意の出力を使用して、ターゲットリストの頻度をカウントします。ここでもコードを見ることができます:

    frequencyOfElt xs=ans
       where ans=countElt(unique xs) xs
          unique []=[]
      unique xs=(head xs):(unique (filter((/=)(head xs))xs))
      countElt ref target=ans'
             where ans'=zip ref lengths
            lengths=map length $ zipWith($)(map[(=='a'),(==',b'),(==',c')](filter.(==))ref)(repeat target)

    Error:Syntax error in input (unexpected symbol "unique") 

しかし、ghci 6.13では、他のタイプのエラーも表示されています

[(=='a')、(=='、b')、(=='、c')]を使用する目的は何ですか。私が期待すること:ref="abc"とtarget="aabbaacc"の場合、

    zipWith($) (map filter ref)(repeat target)

["aaaa"、 "bb"、 "cc"]が表示されたら、これにマップの長さを使用して頻度を取得できます。ここでは、使用する参照[(=='a')、(==' 、b')、(=='、c')]

ここにいくつかの論理エラーがあると思います[(=='a')、(=='、b')、(=='、c')]。

4

2 に答える 2

22

全体を自分で書きたいのか、それともいくつかの標準的な関数で構成してもいいのか、ということはありませんでした。

import Data.List

g s = map (\x -> ([head x], length x)) . group . sort $ s

-- g = map (head &&& length) . group . sort     -- without the [...]

それをコーディングするための標準的なquick-n-dirty方法です。


さて、あなたの最初のアイデアは、ポイントフリースタイルでコーディングすることでした(私の頭の中で特定の曲が演奏されています...):

frequencyOfElt :: (Eq a) => [a] -> [(a,Int)]
frequencyOfElt xs = countElt (unique xs) xs     -- change the result type
  where 
    unique [] = []
    unique (x:xs) = x : unique (filter (/= x) xs)  

    countElt ref target =   -- Code it Point-Free Style  (your original idea)
      zip 
        ref $               -- your original type would need (map (:[]) ref) here
        map length $
          zipWith ($)       -- ((filter . (==)) c) === (filter (== c))
            (zipWith ($) (repeat (filter . (==))) ref)  
            (repeat target)

ここでタイプをより合理的なところで変更しました[a] -> [(a,Int)]。ご了承ください

zipWith ($) fs (repeat z) === map ($ z) fs
zipWith ($) (repeat f) zs === map (f $) zs === map f zs

したがって、コードは次のように単純化されます

    countElt ref target =  
      zip 
        ref $              
        map length $
          map ($ target)      
            (zipWith ($) (repeat (filter . (==))) ref)  

その後

    countElt ref target =  
      zip 
        ref $              
        map length $
          map ($ target) $
            map (filter . (==)) ref

しかしmap f $ map g xs === map (f.g) xs、そう

    countElt ref target =  
      zip 
        ref $              
        map (length . ($ target) . filter . (==)) ref      -- (1)

これは、リスト内包表記で書かれた(私の好みでは)少し明確ですが、

    countElt ref target =  
        [ (c, (length . ($ target) . filter . (==)) c) | c <- ref] 
     == [ (c,  length ( ($ target) ( filter (== c))))  | c <- ref]     
     == [ (c,  length $ filter (== c) target)          | c <- ref]     

これにより、(1)をさらに次のように書き直すことができます。

    countElt ref target =  
      zip <*> map (length . (`filter` target) . (==)) $ ref

しかし、ポイントフリーコードへのこの執着はここでは無意味になります。


したがって、読み取り可能なリスト内包に戻ると、nubあなたと同等の標準関数を使用してunique、あなたのアイデアは次のようになります。

import Data.List

frequencyOfElt xs = [ (c, length $ filter (== c) xs) | c <- nub xs]

このアルゴリズムは実際には2次式( )である~ n^2ため、上記の最初のバージョンよりも劣っています。sort~ n log(n)


ただし、このコードは、同等の変換の原則によってさらに操作できます。

  = [ (c, length . filter (== c) $ sort xs) | c <- nub xs]

...リストでの検索は、ソートされたリストでの検索と同じであるためです。ここでもっと仕事をする-それは報われるでしょうか?..

  = [ (c, length . filter (== c) $ sort xs) | (c:_) <- group $ sort xs]

... 右?しかし、今では、groupすでにそれらをによってグループ化していたので、 :によってすでに行われた作業を繰り返すために呼び出しを行う(==)必要はありません。filtergroup

  = [ (c, length . get c . group $ sort xs) | (c:_) <- group $ sort xs]
            where get c gs = fromJust . find ((== c).head) $ gs

  = [ (c, length g) | g@(c:_) <- group $ sort xs]

  = [ (head g, length g) | g <- group (sort xs)]

  = (map (head &&& length) . group . sort) xs

ではない?そして、これが、この投稿の冒頭からの同じ線形アルゴリズムであり、実際には、隠された一般的な計算を除外しコードから派生し、再利用とコードの簡素化に利用できるようにしています。

于 2012-11-22T17:18:03.260 に答える
12

multiset-0.1の使用:

import Data.Multiset

freq = toOccurList . fromList 
于 2012-11-22T21:19:09.517 に答える