Проблема
Предположим, что у нас есть список xs
(возможно, очень большой), и мы хотим проверить, что все его элементы одинаковы.
Я придумал различные идеи:
Решение 0
проверяя, что все элементы в tail xs
равны head xs
:
allTheSame :: (Eq a) => [a] -> Bool
allTheSame xs = and $ map (== head xs) (tail xs)
Решение 1
проверяя, что length xs
равна длине списка, полученному с помощью элементов из xs
, в то время как они равны head xs
allTheSame' :: (Eq a) => [a] -> Bool
allTheSame' xs = (length xs) == (length $ takeWhile (== head xs) xs)
Решение 2
рекурсивное решение: allTheSame
возвращает True
, если первые два элемента из xs
равны, а allTheSame
возвращает True
в остальной части xs
allTheSame'' :: (Eq a) => [a] -> Bool
allTheSame'' xs
| n == 0 = False
| n == 1 = True
| n == 2 = xs !! 0 == xs !! 1
| otherwise = (xs !! 0 == xs !! 1) && (allTheSame'' $ snd $ splitAt 2 xs)
where n = length xs
Решение 3
разделите и покорите:
allTheSame''' :: (Eq a) => [a] -> Bool
allTheSame''' xs
| n == 0 = False
| n == 1 = True
| n == 2 = xs !! 0 == xs !! 1
| n == 3 = xs !! 0 == xs !! 1 && xs !! 1 == xs !! 2
| otherwise = allTheSame''' (fst split) && allTheSame''' (snd split)
where n = length xs
split = splitAt (n `div` 2) xs
Решение 4
Я просто подумал об этом, когда писал этот вопрос:
allTheSame'''' :: (Eq a) => [a] -> Bool
allTheSame'''' xs = all (== head xs) (tail xs)
Вопросы
-
Я думаю, что решение 0 не очень эффективно, по крайней мере, с точки зрения памяти, потому что
map
построит другой список, прежде чем применятьand
к его элементам. Я прав? -
Решение 1 по-прежнему не очень эффективно, по крайней мере, с точки зрения памяти, потому что
takeWhile
снова создаст дополнительный список. Я прав? -
Решение 2 является хвостовым рекурсивным (справа?), и оно должно быть довольно эффективным, потому что оно вернет
False
, как только(xs !! 0 == xs !! 1)
будет False. Я прав? -
Решение 3 должно быть лучшим, поскольку его сложность должна быть O (log n)
-
Решение 4 выглядит для меня довольно Haskellish (это?), но оно, вероятно, такое же, как Solution 0, потому что
all p = and . map p
(из Prelude.hs). Я прав? -
Есть ли еще лучшие способы написания
allTheSame
? Теперь я ожидаю, что кто-то ответит на этот вопрос, сказав мне, что есть встроенная функция, которая делает это: я искал hoogle, и я ее не нашел. Во всяком случае, поскольку я изучаю Haskell, я считаю, что для меня это было хорошим упражнением:)
Любые другие комментарии приветствуются. Спасибо!