0

zeros という関数を定義する必要があります。この関数は、2 つのリストの入力を受け取り、ブール値を返します。ブール値は、数値 0 が各リストに同じ回数出現する場合は True を返し、それ以外の場合は false を返します。

これは私の宿題の最後の質問であり、問​​題を解決して機能させることができましたが、コードの量を減らす方法を誰かが見つけられるかどうか疑問に思いました。アイデアは大歓迎です。これまでの私のコードは次のとおりです。

x :: Int
x = 0 
instances::[Int]->Int
instances [] = 0
instances (y:ys)
    | x==y = 1+(instances ys)
    | otherwise = instances ys



zeros :: [Int] -> [Int] -> Bool
zeros [] [] = False
zeros x y
       | ((instances x) == (instances y)) = True
       | otherwise = False
4

6 に答える 6

3

これは宿題なので、あまり多くを与えることなく、ここにいくつかのヒントがあります。

リスト内包表記についてまだ知っていますか? この場合、それらは役に立ちます。たとえば、これらをif式と組み合わせて、次のようにすることができます。

*Main> let starS s = [if c == 's' then '*' else ' ' | c <- s]
*Main> starS "schooners"
"*       *"

それらを使用してフィルタリングを行うこともできます。例えば:

*Main> let findFives xs = [x | x <- xs, x == 5]
*Main> findFives [3,7,5,6,3,4,5,7,5,5]
[5,5,5,5]

どちらも完全な答えではありませんが、これらの構造を状況に適応させる方法を理解するのは難しくありません。

ここで実際にガードが必要かどうかも検討する必要があります。たとえば、これはあなたのものと同じスタイルのガードで書かれた関数です:

lensMatch [] [] = True
lensMatch xs ys
             | ((length xs) == (length ys)) = True
             | otherwise = False

同じことをする関数があります!

lensMatch' xs ys = length xs == length ys

それらが同じであることがわかります。最初のテスト:

*Main> lensMatch [1..4] [1..4]
True
*Main> lensMatch [1..4] [1..5]
False
*Main> lensMatch [] [1..5]
False
*Main> lensMatch [] []
True

そして2番目のテスト:

*Main> lensMatch' [1..4] [1..4]
True
*Main> lensMatch' [1..4] [1..5]
False
*Main> lensMatch' [] [1..5]
False
*Main> lensMatch' [] []
True

最後に、上記の sblom のコメントに強く同意します。zeros [] []する必要がありますTrue!次のステートメントについて考えてみましょう:「セット s の各アイテム x について、x > 0」。セット s が空の場合、ステートメントは真です。s には項目がまったくないため、これは true です。これは私には似たような状況のように思えます。

于 2012-04-24T00:26:39.303 に答える
2

誰もfoldrまだ使用を提案していないとは信じられません。最短または最良の定義ではありませんが、IMO は最も教育的です。

instances :: Eq a => a -> [a] -> Int
instances n = foldr incrementIfEqual 0
    where incrementIfEqual x subtotal
              | x == n = subtotal + 1
              | otherwise = subtotal

zeros :: Num a => [a] -> [a] -> Bool
zeros xs ys = instances 0 xs == instances 0 ys

の非常に簡単な定義ですがinstances、私が思いついたのは基本的にAbizernと同じです。

instances :: Eq a => a -> [a] -> Int
instances x = length . filter (==x)
于 2012-04-24T01:00:19.367 に答える
1

各リストをフィルタリングしてゼロだけを取得し、リストの長さを比較してそれらが等しいかどうかを確認することにより、これを 1 回のパスで実行することを考えましたか?

zeroCompare xs ys = cZeroes xs == cZeroes ys
  where
    cZeroes as = length $ filter (== 0) as
于 2012-04-23T23:51:05.133 に答える
0

lengthandの代わりにfilter、 predicate の結果を取得し、pそれを 0 または 1 に変換して、結果を合計できます。

count p = sum . map (fromEnum.p)

--or

import Data.List
count p = foldl' (\x -> (x+).fromEnum.p) 0

あなたの場合、pもちろん(==0)です。usingBoolへの変換は非常に便利なトリックです。IntfromEnum

于 2012-04-24T08:33:45.600 に答える
0

もう 1 つのアイデアは、両方のリストを同時に処理することです。これは少し長くなりますが、理解しやすいものです。

zeros xs ys = cmp xs ys == 0 where
  cmp (0:xs) ys = cmp xs ys + 1
  cmp xs (0:ys) = cmp xs ys - 1
  cmp (_:xs) ys = cmp xs ys
  cmp xs (_:ys) = cmp xs ys
  cmp [] []     = 0
于 2012-04-24T08:47:01.407 に答える
0

問題をヘルパー関数を含む小さな問題に分割します。

これは私がそれを分解する方法です:

  1. 2 つのカウントを比較するメイン関数
  2. カウント ヘルパー関数

まず、リスト内のゼロの数を数える方法が必要です。たとえば、整数リストで 0 の数を検索する場合は、次のようにしてこれに取り組みます。

count :: [Int] -> Int
count xs = foldl (\count num -> if num == 0 then (count + 1) else count) 0 xs

2 つ目: 2 つのリストの数を比較する方法が必要です。基本的に、2 つのリストをパラメーターとして取り、各リストの数を計算し、結果に応じてブール値を返す関数が必要です。たとえば、各リストが int リストの場合、上記のカウントの例に対応します。

    equalZeroes :: [Int] -> [Int] -> Bool
    equalZeroes x y = (count x) == (count y)

次のように、equalZeroes 関数内の where キーワードで count を定義することもできます。

equalZeroes :: [Int] -> [Int] -> Bool
equalZeroes x y = (count x) == (count y)
    where
        count :: [Int] -> Int
        count xs = foldl (\count num -> if num == 0 then (count + 1) else count) 0 xs

このコードを実行すると、そのように関数を呼び出すと、目的のブール値が返されます。

equalZeroes [0,1,4,5,6] [1,4,5,0,0]
-> False

 equalZeroes [0,1,4,5,6] [1,4,5,0]
 -> True
于 2018-02-17T21:33:54.707 に答える