Хаскелл
Моя версія досить довга, тому що я вирішив зосередитись на читанні, я подумав, що було б цікаво формалізувати ваш алгоритм у коді. Я об'єдную підрахунок символів у лівій складці , це в основному сніжки їх разом, і порядок в порядку їх появи в рядку. Мені також вдалося замінити частину алгоритму, яка зазвичай вимагає індексації масиву на згинання списку . Виявляється, ваш алгоритм в основному включає складання списку чисел навпіл та додавання вирівняних чисел разом. Є два випадки згинання, парні списки добре розділені посередині, непарні списки зігнуті навколо центрального елемента, і цей елемент не бере участі в додатку. Fission - це перелік списку та розділення чисел, які вже не є однозначними, наприклад> = 10 . Мені довелося написати власне розгортання , я не впевнений, чи це насправді розгортання , але, здається, робити все, що мені потрібно. Насолоджуйтесь.
import qualified Data.Char as Char
import qualified System.Environment as Env
-- | Takes a seed value and builds a list using a function starting
-- from the last element
unfoldl :: (t -> Maybe (t, a)) -> t -> [a]
unfoldl f b =
case f b of
Just (new_b, a) -> (unfoldl f new_b) ++ [a]
Nothing -> []
-- | Builds a list from integer digits
number_to_digits :: Integral a => a -> [a]
number_to_digits n = unfoldl (\x -> if x == 0
then Nothing
else Just (div x 10, mod x 10)) n
-- | Builds a number from a list of digits
digits_to_number :: Integral t => [t] -> t
digits_to_number ds = number
where (number, _) = foldr (\d (n, p) -> (n+d*10^p, p+1)) (0,0) ds
-- | Bends a list at n and returns a tuple containing both parts
-- aligned at the bend
bend_at :: Int -> [a] -> ([a], [a])
bend_at n xs = let
(left, right) = splitAt n xs
in ((reverse left), right)
-- | Takes a list and bends it around a pivot at n, returns a tuple containing
-- left fold and right fold aligned at the bend and a pivot element in between
bend_pivoted_at :: Int -> [t] -> ([t], t, [t])
bend_pivoted_at n xs
| n > 1 = let
(left, pivot:right) = splitAt (n-1) xs
in ((reverse left), pivot, right)
-- | Split elements of a list that satisfy a predicate using a fission function
fission_by :: (a -> Bool) -> (a -> [a]) -> [a] -> [a]
fission_by _ _ [] = []
fission_by p f (x:xs)
| (p x) = (f x) ++ (fission_by p f xs)
| otherwise = x : (fission_by p f xs)
-- | Bend list in the middle and zip resulting folds with a combining function.
-- Automatically uses pivot bend for odd lists and normal bend for even lists
-- to align ends precisely one to one
fold_in_half :: (b -> b -> b) -> [b] -> [b]
fold_in_half f xs
| odd l = let
middle = (l-1) `div` 2 + 1
(left, pivot, right) = bend_pivoted_at middle xs
in pivot:(zipWith f left right)
| otherwise = let
middle = l `div` 2
(left, right) = bend_at middle xs
in zipWith f left right
where
l = length xs
-- | Takes a list of character counts ordered by their first occurrence
-- and keeps folding it in half with addition as combining function
-- until digits in a list form into any number less or equal to 100
-- and returns that number
foldup :: Integral a => [a] -> a
foldup xs
| n > 100 = foldup $ fission $ reverse $ (fold_in_half (+) xs)
| otherwise = n
where
n = (digits_to_number xs)
fission = fission_by (>= 10) number_to_digits
-- | Accumulate counts of keys in an associative array
count_update :: (Eq a, Integral t) => [(a, t)] -> a -> [(a, t)]
count_update [] x = [(x,1)]
count_update (p:ps) a
| a == b = (b,c+1) : ps
| otherwise = p : (count_update ps a)
where
(b,c) = p
-- | Takes a string and produces a list of character counts in order
-- of their first occurrence
ordered_counts :: Integral b => [Char] -> [b]
ordered_counts s = snd $ unzip $ foldl count_any_alpha [] s
where
count_any_alpha m c
| Char.isAlpha c = count_update m (Char.toLower c)
| otherwise = m
-- | Take two names and perform the calculation
love_chances n1 n2 = foldup $ ordered_counts (n1 ++ " loves " ++ n2)
main = do
args <- Env.getArgs
if (null args) || (length args < 2)
then do
putStrLn "\nUSAGE:\n"
putStrLn "Enter two names separated by space\n"
else let
n1:n2:_ = args
in putStrLn $ show (love_chances n1 n2) ++ "%"
Деякі результати:
"Ромео" "Джульєтта" 97% - важливе емпіричне тестування
"Ромео" "Жульєр" 88% - Сучасна скорочена версія ...
"Хорст Дрейпер" "Джейн" 20%
"Хорст Дрейпер" "Джейн (Кінь)" 70% - Була розробка ...
"Бендер Бендер Родрігес" "Фенні Венчворт" 41% - Бендер каже: " Складення для жінок!"
"Філіп Фрай" "Туранга Ліла" 53% - Ну ви можете зрозуміти, чому для шлюбу з "Марією" "Авраамом" знадобилося 7 сезонів
- 98%
"Джон" "Джейн" 76%