Как получить середину списка в Хаскеле? - PullRequest
16 голосов
/ 14 ноября 2009

Я только начал изучать функциональное программирование, используя Haskel.

Я медленно читаю Лекции Эрика Мейера на 9-м канале (я уже посмотрел первые 4) и в 4-м видео Эрик объясняет, как работает tail, и это меня очаровало.

Я пытался написать функцию, которая возвращает середину списка (2 элемента для четной длины, 1 для нечетной), и я хотел бы услышать, как другие реализуют это в

  • Наименьшее количество кода Haskell
  • Самый быстрый код на Haskell

Если бы вы могли объяснить свой выбор, я был бы очень признателен.

Мой код для начинающих выглядит так:

middle as | length as > 2   = middle (drop 2 (reverse as))
          | otherwise       = as

Ответы [ 17 ]

0 голосов
/ 14 ноября 2009

Очень простое, но нелегкое и не очень лаконичное решение:

middle :: [a] -> Maybe [a]
middle xs
    | len <= 2 = Nothing
    | even len = Just $ take 2 . drop (half - 1) $ xs
    | odd len = Just $ take 1 . drop (half) $ xs
    where 
          len = length xs
          half = len `div` 2
0 голосов
/ 11 июня 2014

Другое однострочное решение:

--
middle = ap (take . (1 +) . signum . (`mod` 2) . (1 +) . length) $ drop =<< (`div` 2) . subtract 1 . length
--
0 голосов
/ 16 ноября 2009

Мне нравится ответ Сванте. Моя версия:

> middle :: [a] -> [a]
> middle [] = []
> middle xs = take (r+1) . drop d $ xs
>  where
>    (d,r) = (length xs - 1) `divMod` 2
0 голосов
/ 16 ноября 2009

Вот моя версия. Это был просто быстрый разбег. Я уверен, что это не очень хорошо.

middleList xs@(_:_:_:_) = take (if odd n then 1 else 2) $ drop en xs
    where n = length xs
          en = if n < 5 then 1 else 2 * (n `div` 4)
middleList xs = xs

Я пытался. :)

Если кому-то захочется прокомментировать и сказать, насколько это решение ужасно или хорошо, я был бы очень признателен. Я не очень хорошо разбираюсь в Хаскеле.

РЕДАКТИРОВАТЬ: Улучшено с предложениями из kmc на # haskell-blah

РЕДАКТИРОВАТЬ 2: теперь может принимать входные списки длиной менее 5.

0 голосов
/ 14 ноября 2009

Это повторяется дважды по списку.

mid xs = m where
  l = length xs
  m | l `elem` [0..2] = xs
  m | odd l = drop (l `div` 2) $ take 1 $ xs
  m | otherwise = drop (l `div` 2 - 1) $ take 2 $ xs
0 голосов
/ 15 ноября 2009

Мое решение, я бы хотел, чтобы все было просто:

middle [] = []
middle xs | odd (length xs) = [xs !! ((length xs) `div` 2)]
          | otherwise = [(xs !! ((length xs) `div` 2)),(reverse $ xs) !! ((length xs)`div` 2)]

Использование !! в Data.List в качестве функции для получения значения по заданному индексу, который в этом случае составляет половину длины списка.

Редактировать: теперь это действительно работает

0 голосов
/ 15 ноября 2009

Я живу за один лайнер, хотя этот пример работает только для нечетных списков. Я просто хочу размять свой мозг! Спасибо за удовольствие =)

foo d = map (\(Just a) -> a) $ filter (/=Nothing) $ zipWith (\a b -> if a == b then Just a else Nothing) (Data.List.nub d) (Data.List.nub $ reverse d)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...