0

編集:私がやろうとしていることを説明するのは難しいですが、ここに試してみてください(コメントから):

私は wordfeud ソルバーを構築しているので、単語といくつかの文字 (両方の文字リスト) があります。これ ( Haskell で文字列内の文字の頻度を見つけるには? ) を両方のリストに適用して、すべての文字の頻度を取得しました。私が今していることは、「単語」文字リストを繰り返し処理し、すべての文字が「文字」文字リストに十分にあるかどうかを確認することです。

関数を両方のリストの項目に適用し、結果を比較することで、2 つのリストを比較する Haskell 関数を作成しました。

比較は次のように行われます。

hasLetters' :: [Char] -> [Char] -> Bool
hasLetters' word letters = (getCharOccurrence (head word) (getCharOccurrences word)) <= (getCharOccurrence (head word) (getCharOccurrences letters))

これは、単語の最初の文字の出現のみを比較します。ただし、すべての単語を比較する必要があります (結果はすべての単語に対して TRUE になる必要があります)。

これを達成する方法がよくわかりません。述語を定義できる「all」メソッドを見つけました。これは非常に優れています。次のようになります。

all (<= (getCharOccurrence (head word) (getCharOccurrences letters))) 

(私はそれが正しいと思います)リストに入るすべてのアイテムが、提供された関数の結果以下であることを確認します。

BUT: 'all' メソッドには別のパラメーターが必要です。これは、述語と比較する対象を定義する「ソース」パラメーターになります。これが単なるリストである場合、これは簡単です。次に、次のようにします。

all (<= (getCharOccurrence (head word) (getCharOccurrences letters))) [0..10]

しかし、問題は次のとおりです。このような結果のリストはありません。次の結果と比較する必要があります。

(getCharOccurrence (head word) (getCharOccurrences letters))

'map' 関数を使用して、'word' char リスト内のすべての文字にこの関数を適用できると考えましたが、その使用方法がわかりません。私はこのように始めました:

map (getCharOccurrence (head word) (getCharOccurrences word)) word

しかし、それは間違っています。

だから私は(私が思うに)必要なもの:上記の関数を「単語」文字リストのすべての文字に適用し、それを述語と比較します。

ただ、考え方が間違っているだけかもしれません。私は完全な Haskell/関数型プログラミングの初心者です。私を助けてください :-)

4

3 に答える 3

3

multisetパッケージの使用:

import Data.MultiSet
compareAll as bs = fromList as `isSubsetOf` fromList bs

また:

import Data.Function
import Data.MultiSet
compareAll = isSubsetOf `on` fromList
于 2012-07-01T03:01:36.137 に答える
2

したがって、私が理解していることからword、形成したい単語を含む文字列と、letters自由に使用できるタイルを表す文字のリストがあります。単語がタイルによって形成されているかどうかを確認します。

ここで、あなたが言及した関数には型があると仮定しています

getCharOccurrence :: Char -> [(Char, Integer)] -> Integer
getCharOccurrences :: [Char] -> [(Char, Integer)]

hasLetters'まず、使用する代わりに Char パラメータを取るように変更する必要がありますhead word

hasLetters' :: Char -> [Char] -> [Char] -> Bool
hasLetters' c word letters = (getCharOccurrence c (getCharOccurrences word)) <= (getCharOccurrence c (getCharOccurrences letters))

次に、上記をマスター関数に組み合わせることができます(それを呼び出しましょうsufficientTiles

sufficientTiles :: [Char] -> [Char] -> Bool
sufficientTiles word letters = and $ map (\c -> hasLetters' c word letters) word

ここで行ったことは、hasLetter'関数を の各文字にマップすることですword。これにより、ブールのリストが得られます。次に、 を使用andして、そのリストのすべての要素が であることを確認しますTrue

于 2012-07-01T00:15:10.850 に答える
1

2 つのリストを比較したいということは理解できたと思います。2 番目のリストに最初のリストと少なくとも同じ数の各要素が含まれている場合、テストは成功します。したがって、少なくとも等しいという制約が必要ですが、順序が役立ちます。

多くの解決策がありますが、最初に頭に浮かぶのは、各リストを並べ替え、一意の要素をグループ化してカウントし、すべての結果が<=次のようになるようにすることです。

someCompare a b = let op :: String -> [(Char,Int)]
                      op = map (head &&& length) . group . sort
                  in [c <= k | (x,c) <- op a, k <- maybeToList (lookup x (op b))]

または、カウンターのマップを使用して、2 つのマップを統合することもできます。

someCompare2 a b =
        let op = foldl' (\m c -> Map.insertWith (+) c 1 m) Map.empty
        in all (<= 0) . Map.elems $ Map.unionWith (+) (op a) (Map.map negate $ op b)

などなど

于 2012-06-30T23:49:56.223 に答える