Как редактировать N-й элемент в списке Haskell?
Я знаю, что xs!!n дает мне n-й элемент в списке, но я не знаю как редактировать N-ый элемент в этом списке. Можете ли вы сказать мне, как я могу редактировать N-й элемент в списке или дать подсказку? Например, как я могу сделать второй элемент " a " и " e " в этом: ["s", "t", "a", "c", "k"]? Спасибо.
3 ответов
поскольку Haskell является функциональным языком, вы не можете редактировать элементы в списках, потому что все является неизменным. Вместо этого вы можете создать новый список с чем-то вроде:
take n xs ++ [newElement] ++ drop (n + 1) xs
однако в Haskell это не рекомендуется. Для получения дополнительной информации вы можете увидеть это сообщение:Haskell заменить элемент в списке
изменение n-го элемента
общей операцией на многих языках является назначение индексированной позиции в массиве. В Python вы можете:
>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]
в
объектив пакет дает эту функциональность с (.~)
оператора. Хотя в отличие от python исходный список не мутирует, скорее возвращается новый список.
> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]
element 3 .~ 9
- это просто функция, а (&)
оператора, часть
объектив пакет, как раз обратное применение функции. Здесь оно с более общим применением функции.
> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]
назначение снова отлично работает с произвольной вложенностью Traversable
s.
> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]
или
> set (element 3) 9 [1,2,3,4,5,6,7]
или если вы хотите произвести эффект нескольких элементов, которые вы можете использовать:
> over (elements (>3)) (const 99) [1,2,3,4,5,6,7]
> [1,2,3,4,99,99,99]
работа с типами, отличными от списков
это не ограничивается только списки, однако, он будет работать с любым типом данных, который является экземпляром из проходимым typeclass.
возьмите, например, тот же метод работает на деревьев форма стандартная тара.
> import Data.Tree
> :{
let
tree = Node 1 [
Node 2 [Node 4[], Node 5 []]
, Node 3 [Node 6 [], Node 7 []]
]
:}
> putStrLn . drawTree . fmap show $ tree
1
|
+- 2
| |
| +- 4
| |
| `- 5
|
`- 3
|
+- 6
|
`- 7
> putStrLn . drawTree . fmap show $ tree & element 1 .~ 99
1
|
+- 99
| |
| +- 4
| |
| `- 5
|
`- 3
|
+- 6
|
`- 7
> putStrLn . drawTree . fmap show $ tree & element 3 .~ 99
1
|
+- 2
| |
| +- 4
| |
| `- 99
|
`- 3
|
+- 6
|
`- 7
> putStrLn . drawTree . fmap show $ over (elements (>3)) (const 99) tree
1
|
+- 2
| |
| +- 4
| |
| `- 5
|
`- 99
|
+- 99
|
`- 99
вы не можете редактировать N-й элемент списка, значения являются неизменяемыми. Вы должны создать новый список. Но из-за неизменности он может делиться частью после измененного элемента с исходным списком.
Итак, если вы хотите применить преобразование к N-му элементу списка (и иметь части до и после идентичных), у вас есть три части
- передняя часть списка перед рассматриваемым элементом, скажем
front
- элемент в вопрос, Скажи
element
- в конце списка после элемента, о котором идет речь, скажите
back
.
тогда вы собирали бы детали
front ++ transform element : back
так что остается, чтобы получить контроль над интересными частями в хорошем смысле.
splitAt :: Int -> [a] -> ([a],[a])
это, splitAt idx list
возвращает первую часть списка, перед индексом idx
как первый компонент пары, а остальные как второй, так что
changeNthElement :: Int -> (a -> a) -> [a] -> [a]
changeNthElement idx transform list
| idx < 0 = list
| otherwise = case spliAt idx list of
(front, element:back) -> front ++ transform element : back
_ -> list -- if the list doesn't have an element at index idx
(Примечание: я начал подсчет элементов в 0, если вы хотите начать подсчет с 1, вам нужно настроить и использовать idx-1
.)