2014-03-07 2 views
0

Я недавно взял на себя изучение Haskell и, на одном из первых уроков, мне сказали научиться управлять списками в первую очередь. Я понимаю, как выбрать элемент списка от его позиции, как этотВозврат элемента списка с использованием позиций

myList = [7, 3, 6, 15, 8] 
    myList !! 3 

Теперь я хотел бы знать, если это возможно, чтобы выбрать позицию, начиная с последнего элемента списка, так же, как то, что я делал в Python с помощью этого

pythonlist = [7, 3, 6, 15, 8] 
    pythonlist[-2] 

ответ

1

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

Но достаточно уверен, что это возможно для доступа списки по индексу, а также со спины:

(!!<) :: [a] -> Int -> a 
l !!< i = l !! i' 
where i' = length l - i - 1 

Я надеюсь, что это достаточно очевидно, как это работает. Это еще более неэффективно, чем обычный доступ, потому что length проходит весь список, но вот он.

+0

Это тоже правильно (!! <) :: [a] -> Int -> а л !! <я = (обратный л) !! я –

+0

Да, возможно, даже бит лучше. – leftaroundabout

+0

Я просто добавлю его ради разнообразия :) –

0

В некоторых случаях да. Вы можете просто переопределить (!!) к:

xs !! i | i >= 0 = xs Data.List.!! i 
     | i < 0 = let n = length xs 
        in xs Data.List.!! (n+i) 

Однако, это не очень большая идея в Haskell из-за лени . Решение выше работает на конечных списках, о чем вы говорите в Python. Однако подумайте о том, что происходит в бесконечном списке: [1..] !! (-2). Сначала оцениваем length [1..], который никогда не заканчивается! Проблема в том, что вы не можете индексировать с конца бесконечного списка.

+0

Чтобы сделать это хотя бы несколько последовательным, я бы скорее определил новый оператор, например '' xs !!! i = xs !! (i 'mod' length list)' ', чтобы дать отрицательные индексы в качестве особого случая« безопасного индексирования путем переноса ». Но на самом деле я бы предпочел не иметь такой возможности вообще, это ИМО более запутанной, чем полезной. – leftaroundabout

1

Вы можете сделать:

(!!<) :: [a] -> Int -> a 
l !!< i = (reverse l) !! i 

Но это означает, что вы не можете использовать отрицательные числа, только положительный индекс, но это будет выглядеть с конца списка.

Или, если вы действительно хотите использовать негативы:

(!!<) :: [a] -> Int -> a 
l !!< i = if i < 0 then l !! (length l + i) else l !! i 
Смежные вопросы