3

char特定の文字列と特定の番号のリストを分割する関数を Haskell で作成しようとしています。

これを行うには、splitAt 関数がまさに数値に必要なものですが、この関数で char を指定することはできません。

例えば

splitAt 5 [1,2,3,4,5,6,7,8,9,10]

与える

([1,2,3,4,5],[6,7,8,9,10])

これはまさに、タプルの左側にある 5 で必要なものです。charしかし、今は aと stringでこれをやりたいと思っています。ただし、2 番目の引数にsplitAtは and のみを使用します。int私が欲しい

splitAt 'c' "abcde"

その結果

("abc", "de")

私はの方向に何かを探しています

splitAt (findIndex 'c' "abcde") "abcde"

しかし、関数findIndexは型の何かをMaybe Int返しsplitAtInt. 次に、次のことを試しました

splitAt (head (findIndices (== 'c') "abcde")) "abcde"

これは可能な解決策ですが、次を返します

("ab","cde")

タプルの反対側に c を付けます。cに追加できますがsucc、char が Z の場合の結果はどうなりますか?

簡単に改造する方法はありますか

splitAt (findIndex 'c' "abcde") "abcde"

仕事?

4

4 に答える 4

2

この関数を使用して fromMaybe、Maybe から結果を取得できます。次に例を示します。

splitlist = splitAt (fromMaybe 0 (findIndex 'c' "abcde") "abcde")

fromMaybe :: a -> Maybe a -> a

fromMaybe 関数はデフォルト値と Maybe 値を取ります。Maybe が Nothing の場合、デフォルト値が返されます。それ以外の場合は、Maybe に含まれる値を返します。(ソース)。

デフォルト値が 0 に設定されている場合、findIndexNothingが splitAt の結果を返す("",list)場合、同じケースですが、デフォルト値がlength list最終結果に設定されている場合は になります(list,"")

于 2012-12-09T18:23:34.123 に答える
2

を使用できますfindIndex。ラップを解除しMaybeて追加するだけです。

import Data.List

splitAfter :: (a-> Bool) -> [a] -> ([a],[a])
splitAfter this xs = case findIndex this xs of
    Nothing -> (xs,[])
    Just n -> splitAt (n+1) xs

たとえば、与える

*Main> splitAfter (=='c') "abcde"
("abc","de")

おそらく、簡単に回復できる方法でエラーをエンコードするための便利なデータ型です。デフォルト値を使用する関数maybe :: b -> (a -> b) -> Maybe a -> bと、2 つのケースを別々に処理する関数もあります。

splitAfter' :: (a-> Bool) -> [a] -> ([a],[a])
splitAfter' this xs = maybe (xs,[]) 
                  (\n -> splitAt (n+1) xs) 
                  (findIndex this xs)

これも機能します。例えば

*Main> splitAfter' (==5) [1..10]
([1,2,3,4,5],[6,7,8,9,10])
于 2012-12-09T18:19:02.727 に答える
1

と が与えられるc :: Chars :: String、次のように書くことができます。

splitAt ((1+) $ fromJust $ findIndex (==c) s) s

しかし

  1. 入っていない場合cは例外が発生しますs
  2. sあなたは2回トラバースします

Maybe代替手段は

maybe Nothing (\x -> splitAt (1+x) s) (findIndex (==c) s)

「else value」を設定できます(Nothing私の例では)。

独自の関数を次のように書くことができます

splitAt' :: Char -> String -> (String, String)
splitAt' _ [] = ("", "")
splitAt' c (x:xs) | c == x = ([c], xs)
                  | True   = (x:cs, ys) where (cs, ys) = splitAt' c xs

次に、(s, "")if not cinを取得しsます。

于 2012-12-09T18:28:58.250 に答える
0

これは別の方法で、リストのインデックスをいじることはありません。

breakほぼあなたが望むものです。再利用しましょう。一致する要素を、2 番目の出力リストの先頭ではなく、最初の出力リストの最後に含める必要があります。

import Control.Arrow ((***))

breakAfter :: (a -> Bool) -> [a] -> ([a], [a])
breakAfter p xs = map fst *** map fst $ break snd (zip xs $ False : map p xs)

仕組み:

  1. 入力リストをペアのリストに変換します ( zip)。各ペアの最初の要素は、元のリストから取得されます。ペアの 2 番目の要素は、リストのの要素が探している要素であるBoolかどうかを示します。これが、私たちが言う理由です--- 今言った場合、 の動作を正確に再現します。最初に余分なものを入れることが重要です。False : map p xsmap p xsbreakFalse
  2. 再利用しbreakます。条件は、各ペアの 2 番目の要素にエンコードされます。
  3. それらすべてを捨てますBool。もう必要ありません。
于 2012-12-09T19:19:28.717 に答える