2010-11-04 5 views
1

У меня возникли проблемы, выясняя эту функцию из:Сравнение элементов в списке пар

Определить функцию maybeA :: [(String, a)] -> Maybe (String, a, a), которая принимает список пар. Если список входных данных имеет две пары (a1, b1), (a2, b2) такие, что a1 = a2, функция возвращает кортеж, содержащий a1 и b1, b2. В противном случае он ничего не возвращает. Пример: maybeA [("a", 1), ("b", 2), ("b", 3)] вернет Just ("b", 2, 3).

Какие-либо намеки?

ответ

1

Если вы просто ищете для первых двух случаев, когда две пары имеют те же первые два элемента, то следующее определение будет работать:

maybeA :: [(String, a)] -> Maybe (String, a, a) 
maybeA = maybeA' [] 
    where 
    maybeA' _ []   = Nothing 
    maybeA' as ((x,y):xys) = 
     case lookup x as of 
     Just y' -> Just (x,y,y') 
     Nothing -> maybeA' ((x,y):as) xys 

Обратите внимание, что если вы передаете его список, содержащий (a1, b1), (a2, b2) и (a3, b3) где a1 == a2 и a2 == a3, он будет возвращать только Just (a1, b1,b2) не Just (a1, b1,b2,b3) (который не будет даже одного и того же типа).

Проектирование функции, которая делает это в качестве упражнения :-)

+0

Благодарим за помощь! Ваш подход должен принимать 2 аргумента, которые имеют 2 списка? Поскольку возможно A '_ [] = Nothing, тип MaybeA' должен быть :: [(String, a)] -> [(String, a)] -> Maybe (String, a, a) правильно? И это будет работать, если в каждом списке будет всего одна пара. Есть ли способ, которым эта функция может принимать только один список из многих пар? Я действительно ценю ваш ответ, хотя :) – user496579

+3

Вероятно, это то, что ожидает домашняя проблема, но обратите внимание, что это довольно ужасный алгоритм на практике, потому что 'lookup' должен выполнять линейный поиск по списку. Бинарное дерево, такое как 'Data.Map', будет намного лучше. –

3

Вот это «комбинатор подход» - преодолев проблему в небольшие, простые шаги, и применяя эти шаги один после следующего состава с использованием функции :

import Data.List (sort, groupBy) 
import Data.Maybe (listToMaybe) 
import Data.Function (on) 

maybeA = fmap formatAnswer . listToMaybe . dropWhile (null . drop 1) . 
     groupBy ((==) `on` fst) . sort 
    where 
    formatAnswer ((a, b1):(_, b2):_) = (a, b1, b2) 

Некоторые примечания:

  • fmap применяет функцию к значению внутри Maybe, если он существует. (fmap работает аналогичным образом и на многих других типах.)
  • (==) `on ` fst проверяет, равны ли два кортежа на их первых элементах.
  • sort сравнивает как элементов в кортеже, но использует словарь. Поэтому он работает здесь, но иногда он меняет порядок b1 и b2. Если это для вас проблема, используйте вместо этого sortBy (comparing fst). sortBy находится в модуле Data.List, а comparing - в модуле Data.Function.
Смежные вопросы