我提出了一个不真实的问题:在词汇表中找到所有回文单词对,所以我在下面写了解决方案,
import Data.List
findParis :: Ord a => [[a]] -> [[[a]]]
findPairs ss =
filter ((== 2) . length)
. groupBy ((==) . reverse)
. sortBy (compare . reverse)
$ ss
main = do
print . findPairs . permutations $ ['a'..'c']
-- malfunctioning: only got partial results [["abc","cba"]]
-- expected: [["abc","cba"],["bac","cab"],["bca","acb"]]
如果值得尝试,你可以帮忙纠正吗?
@Solution
受益于@David Young @chi
评论,调整后的工作代码如下:
import Data.List (delete)
import Data.Set hiding (delete, map)
findPairs :: Ord a => [[a]] -> [([a], [a])]
findPairs ss =
let
f [] = []
f (x : xs) =
let y = reverse x
in
if x /= y
then
let ss' = delete y xs
in (x, y) : f ss'
else f xs
in
f . toList
. intersection (fromList ss)
$ fromList (map reverse ss)
答案 0 :(得分:2)
import Data.List
import Data.Ord
-- find classes of equivalence by comparing canonical forms (CF)
findEquivalentSets :: Ord b => (a->b) -> [a] -> [[a]]
findEquivalentSets toCanonical =
filter ((>=2) . length) -- has more than one
-- with the same CF?
. groupBy ((((== EQ) .) .) (comparing toCanonical)) -- group by CF
. sortBy (comparing toCanonical) -- compare CFs
findPalindromes :: Ord a => [[a]] -> [[[a]]]
findPalindromes = findEquivalentSets (\x -> min x (reverse x))
只要我们可以为我们的元素分配一些有效可计算的规范形式(CF),这个函数就可以找到很多种等价。
当寻找回文对时,如果一个是另一个的反向,则两个字符串是等价的。 CF是字典上较小的字符串。
findAnagrams :: Ord a => [[a]] -> [[[a]]]
findAnagrams = findEquivalentSets sort
在这个例子中,如果一个是另一个的字谜,则两个字符串是等价的。 CF是排序字符串(香蕉→aaabnn)。
同样我们可以找到SOUNDEX等价物等等。
这不是非常有效,因为需要在每次比较时计算CF.我们可以以可读性为代价来缓存它。
findEquivalentSets :: Ord b => (a->b) -> [a] -> [[a]]
findEquivalentSets toCanonical =
map (map fst) -- strip CF
. filter ((>=2) . length) -- has more than one
-- with the same CF?
. groupBy ((((== EQ) .) .) (comparing snd)) -- group by CF
. sortBy (comparing snd) -- compare CFs
. map (\x -> (x, toCanonical x)) -- pair the element with its CF
答案 1 :(得分:1)
这是您可能想要考虑的方法。
使用sort
意味着有一些键控函数word2key
可以为回文对的两个单词产生相同的值。我想到的第一个是
word2key w = min w (reverse w)
因此,将键控函数映射到单词列表,排序,按等号分组,取长度为2的组,然后从键中恢复两个单词(使用键等于单词或反过来。
为了清楚起见,写了几个本地定义,给出了:
findPals :: (Ord a, Eq a) => [[a]] -> [[[a]]]
findPals = map (key2words . head) .
filter ((== 2) . length) .
groupBy (==) .
sort .
(map word2key)
where word2key w = min w (reverse w)
key2words k = [k, reverse k]
修改强>
我在一个陈旧的窗口中发布了我的答案而没有刷新,所以错过了从上午那里得到的非常好的回复。上方。
Mea culpa 。
所以我要提到两个答案都是众所周知的变体(在Perl圈子中)“Schwartzian transform”,它本身应用了一个共同的数学模式 - h = f' . g . f
- 翻译一个任务到任务更容易的替代表示,完成工作,然后转换回原始表示。
Schwartzian变换使用相应的键对值进行元组化,按键排序,然后将原始值从键/值元组中拉回。
我上面提到的小黑客是基于key2words
是word2key
的非确定性反向关系的事实。只有当两个单词具有相同的密钥时才有效,但这正是问题中的情况,并且由filter
保险。
overAndBack :: (Ord b, Eq c) => (a -> b) -> ([b] -> [c]) -> (c -> d) -> [a] -> [d]
overAndBack f g f' = map f' . g . sort . map f
findPalPairs :: (Ord a, Eq a) => [[a]] -> [[[a]]]
findPalPairs = overAndBack over just2 back
where over w = min w (reverse w)
just2 = filter ((== 2) . length) . groupBy (==)
back = (\k -> [k, reverse k]) . head
哪个演示为
*Main> findPalPairs $ words "I saw no cat was on a chair"
[["no","on"],["saw","was"]]
感谢您提出的好问题。