web-dev-qa-db-ja.com

Haskellのリストの最後の要素を取得する最速の方法

Haskellのリストの最後の要素を取得する最速の方法は何ですか。また、次の反復では、リストの最初と最後の要素を削除します。最もエレガントな方法は何ですか?リストの理解を試みていますが、それはあまり効率的ではありません!

28
Dilawar

lastinitは、1回限りの仕事をうまく行います。ただし、両方ともO(n)なので、リストの両端を頻繁に操作する必要がある場合は、暗黙のように思われるかもしれませんが、 Data.Sequence 代わりに、O(1)両端のアイテムの挿入と削除をサポートします。

38
hammar

last関数 を使用して、リストの最後の要素を取得できます。

最初と最後の要素を削除する方法については、(init . tail)、しかしそれがどれほど効率的かはわかりません。

Learn You A Haskell のこの画像は、リスト関数をかなりよく示していると思います。

illustration of list functions

79
icktoofay

Preludeの実装はまだ投稿されていないので投稿します。

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

関数名をlistLastに変更したため、通常のPreludeと競合することなく実行できることに注意してください。もちろん、import Prelude hiding(last)を実行できます。

6
user1429980

この答えは、(空のリストのような)奇妙な条件を最大限に柔軟な方法で処理し、いくつかのライブラリ関数を使用して小さな関数から大きな関数を構築することに焦点を当てています。それはnotで、リストについて最初に学習した人にとっては最良の答えですが、それよりも数ステップ先です。

以下のために、あなたは必要になります

_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
_

だからあなたは多分得ることができます

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

_>=>_は、一種の後方モナド合成です。 _init' >=> tail'_は、_init'_を引数に適用して_Maybe [a]_を取得する関数です。 Nothingを取得すると、それを返します。 _Just xs_を取得した場合、xsに_tail'_を適用し、それを返します。

これから、0、1、または2要素のリストを空のリストにトリムするトリマーを簡単に作成できます。

_trim :: [a] -> [a]
trim = maybe [] id . trim'
_
0
dfeuer

最初と最後を削除するには:

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

または多分

init (drop 1 l)

これにより、ほぼ最適なコードも生成されます。

0
nulvinge