文字列から特定の重複を削除する方法を知りたいです。例は次のとおりです。
"|Hello|| My|| Name|| Is|| XYZ|"
次のようになる必要があります。
"|Hello| My| Name| Is| XYZ|"
ありがとう
文字列から特定の重複を削除する方法を知りたいです。例は次のとおりです。
"|Hello|| My|| Name|| Is|| XYZ|"
次のようになる必要があります。
"|Hello| My| Name| Is| XYZ|"
ありがとう
自分で許可する場合Data.List.Split
(そうするべきです!)、文字列を次のように単語に分割できます
splitOn "|" "|Hello|| My|| Name|| Is|| XYZ|"
利回り
["","Hello",""," My",""," Name",""," Is",""," XYZ",""]
""
出現するすべての単語をwithに置き換えてから"|"
、単語を結合します。これは単に次のように を呼び出すだけですconcatMap
:
concatMap (\s -> if s == "" then "|" else s) $
splitOn "|" "|Hello|| My|| Name|| Is|| XYZ|"
利回り
"|Hello| My| Name| Is| XYZ|"
別の方法として"||"
、部品を分割して結合し、その間に挿入することもでき"|"
ます。これだけ
intercalate "|" $ splitOn "||" "|Hello|| My|| Name|| Is|| XYZ|"
さらに別の代替手段であり、奇妙なエッジケースで失敗した場合に修正するのがおそらく最も簡単なのは、正規表現を使用することです。次のようになります。
subRegex (mkRegex "\\|\\|") "|Hello|| My|| Name|| Is|| XYZ|" "|"
|
簡単に修正できるという意味を示すために、任意の数のs を 1 つの s だけに減らしたいと想像してください|
。正規表現ソリューションでは、正規表現を次のように変更するだけです。
> subRegex (mkRegex "\\|+") "|||Hello||||||| My|| Name|||| Is|| XYZ|||||" "|"
"|Hello| My| Name| Is| XYZ|"
非常にシンプルで明白な解決策は、ダブル ヘッドでパターン マッチを行うことです。
foo :: Char -> String -> String
foo elem (xa:xb:xs) = ...
次に、xa
が と等しいかどうかを確認xb
し、残りの部分と一緒に両方を返すか、重複している場合は 1 つだけを返し、1 文字前に移動します。
ここでの重要な問題は、2 つ以上続けて何をするかです|
。ここで提供されるソリューションは、この特定の側面で大きく異なります。
の重複排除を||||
「別の | の前に | を削除する」と|
解釈"Hello ||||"
し"Hello |||"
ますか?
の重複排除を||||
「|| のすべてのペアを 1 つの | に減らす」と解釈"Hello ||||"
し"Hello ||"
ますか?
の重複排除を||||
「特異点のみが発生するまで文字列を減らす」と解釈"Hello ||||"
し"Hello |"
ますか?
したがって、(1) の解決策が提案されました。(2) と (3) のソリューションは、互いに同様の方法で構築できます。
(2) の解決策:
dedup c (x:y:xs) | x == c && x == y = x: dedup c xs
dedup c (x:xs) = x: dedup c xs
dedup c _ = []
(3) の解決策:
dedup c (x:y:xs) | x == c && x == y = dedup c (y:xs)
dedup c (x:xs) = x: dedup c xs
dedup c _ = []
ペアが見つかったときに追加するタイミングを微調整するだけで|
、動作に大きな違いが生じます。
import Data.List.Split(splitOn)
removeDup d = concat . map rep . splitOn d
where
rep s = if null s then d else s
> removeDup "|" "|Hello|| My|| Name|| Is|| XYZ|"
"|Hello| My| Name| Is| XYZ|"
ghci> :m Data.List
ghci> let myGroupFunc = groupBy (\a b -> a == '|' && b == '|')
ghci> map head $ myGroupFunc "|Hello|| My|| Name|| Is|| XYZ|"
"|Hello| My| Name| Is| XYZ|"
ghci>
groupBy
タイプ(a -> a -> Bool) -> [a] -> [[a]]
です。関数とリストを受け取り、リストのリストを返します。groupBy
type の関数(a -> a -> Bool)
(これを と呼びますf
) を取り、リストをトラバースして、時間の 2 つの要素を渡します。f
が返される場合True
、2 つの要素が同じサブリストにまとめられます。一方、f
が返される場合False
、新しいサブリストが作成されます。
実験する 1 つの方法groupBy
は、次のように設定f
すること(==)
です。
ghci> groupBy (==) "aaabbbcccdeffg"
["aaa","bbb","ccc","d","e","ff","g"]
これにより、要素が等しい場合またはreturn の場合に要素がグループ化されるため、同じ文字がグループ化されます(==)
。True
(余談ですが、Haskell では、 aString
は実際には a[Char]
であるため、 の同等の表現"aaabbbcccdeffg"
は次のようになります。['a','a','a','b','b','b','c','c','c','d','e','f','f',g']
結果の同等の表現は次のとおりです。
[['a','a','a'],['b','b','b'],['c','c','c'],['d'],['e'],['f','f'],['g']]
.)
groupBy (==)
サンプル入力を試してみましょう。
ghci> groupBy (==) "|Hello|| My|| Name|| Is|| XYZ|"
["|","H","e","ll","o","||"," ","M","y","||"," ","N","a","m","e","||"," ","I","s","||"," ","X","Y","Z","|"]
要素のペアが同じになるたびに、要素をグループ化することに注意してください。しかし、それはあなたが望むものではありませ"ll"
ん"Hello"
.
そのため、要素のペアが同じであり、それらが必要な文字である場合groupBy
にのみ返すように、渡される関数を変更します: :True
'|'
ghci> groupBy (\a b -> a == '|' && b == '|') "|Hello|| My|| Name|| Is|| XYZ|"
["|","H","e","l","l","o","||"," ","M","y","||"," ","N","a","m","e","||"," ","I","s","||"," ","X","Y","Z","|"]
まとめたい文字のみをグループ化することに注意してください'|'
。ここで、複製された要素の 1 つだけが必要なため、Char
それぞれの最初の要素String
を取得して結合し、結果を取得できます。
ghci> map head $ groupBy (\a b -> a == '|' && b == '|') "|Hello|| My|| Name|| Is|| XYZ|"
"|Hello| My| Name| Is| XYZ|"
これは、この回答の冒頭からの解決策です。式f
を使用せずに直接適用することを受け入れてください。let