Подтвердить что ты не робот

Самый быстрый способ получить последний элемент списка в Haskell

Каков самый быстрый способ получить последний элемент списка в Haskell. Также на следующей итерации я хочу удалить первый и последний элемент списка. Какой самый элегантный способ сделать это? Я пытаюсь понять список, но это выглядит не очень эффективно!

4b9b3361

Ответ 1

last и init отлично справятся с заданием для одноразового использования. Однако они оба O (n), поэтому, если вам нужно часто манипулировать обоими концами списка, как вы, кажется, подразумеваете, вы можете рассмотреть возможность использования Data.Sequence, который поддерживает O (1) вставку и удаление элементов с обоих концов.

Ответ 2

Вы можете использовать функцию last, чтобы получить последний элемент списка.

Как удалить первый и последний элементы, вы можете использовать (init . tail), но я не знаю, насколько это эффективно.

Я думаю, что это изображение из Learn You A Haskell показывает, что функции списка довольно хорошо:

illustration of list functions

Ответ 3

Я опубликую реализацию Prelude, поскольку она еще не была опубликована:

listLast :: [a] -> a
listLast [x] = x --base case is when there just one element remaining
listLast (_:xs) = listLast xs --if there anything in the head, continue until there one element left
listLast [] = error "Can't do last of an empty list!"

Обратите внимание, что я изменил имя функции на listLast, чтобы ее можно было запустить без конфликта с обычной прелюдией. Вы могли бы, конечно, сделать import Prelude hiding(last).

Ответ 4

Чтобы удалить первый и последний:

take (len(l)-2) (drop 1 l)

или, возможно,

init (drop 1 l)

Это также приводит к почти оптимальному коду.

Ответ 5

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

Для следующего вам понадобится

import Control.Monad ((>=>))

и вам нужно либо использовать GHC 7.10, либо импортировать Data.List (uncons) или определить

uncons :: [a] -> Maybe (a, [a])
uncons [] = Nothing
uncons (x:xs) = Just (x,xs)

Вы можете написать безопасную форму init следующим образом:

init' :: [x] -> Maybe [x]
init' = foldr go Nothing
  where
    go x mxs = Just (maybe [] (x:) mxs)

Версия tail может быть записана

tail' :: [a] -> Maybe [a]
tail' = fmap snd . uncons

Итак, вы можете получить iffied

trim' :: [a] -> Maybe [a]
trim' = init' >=> tail'

>=> представляет собой своего рода обратную монадическую композицию. init' >=> tail' - это функция, которая применяет init' к своему аргументу для получения Maybe [a]. Если он получает Nothing, он возвращает это. Если он получает Just xs, он применяет tail' к xs и возвращает это.

Из этого вы можете легко создать триммер, который обрезает списки с 0, 1 или 2 элементами до пустых списков:

trim :: [a] -> [a]
trim = maybe [] id . trim'

Ответ 6

(head.reverse) [1..100]

Является альтернативой last для получения последнего элемента.

drop 1 (take (length [1..100] - 1) [1..100])

удаляет первый и последний элементы списка. Источник для drop и take выглядит так, как будто он быстрее, чем (init . tail).

(reverse.drop 1) ((reverse.drop 1) [1..100])

- другой вариант. Но я думаю, что медленнее из-за двойного разворота.